/// © 2015 Nathan Rugg <nmrugg@gmail.com> | MIT
/// See LICENSE for more details.

/* jshint noarg:true, boss:true, unused:strict, strict:true, undef:true, noarg: true, forin:true, evil:true, newcap:false, -W041, -W021, worker:true, browser:true, node:true */

/* global setImmediate, setTimeout, window, onmessage */

/** xs */
///NOTE: This is the master file that is used to generate lzma-c.js and lzma-d.js.
///      Comments are used to determine which parts are to be removed.
///
/// cs-ce (compression start-end)
/// ds-de (decompression start-end)
/// xs-xe (only in this file start-end)
/// co    (compression only)
/// do    (decompression only)
/** xe */

var LZMA = (function() {
  'use strict';

  var /** cs */
    action_compress = 1,
    /** ce */
    /** ds */
    action_decompress = 2,
    /** de */
    action_progress = 3,
    wait = typeof setImmediate == 'function' ? setImmediate : setTimeout,
    __4294967296 = 4294967296,
    N1_longLit = [4294967295, -__4294967296],
    /** cs */
    MIN_VALUE = [0, -9223372036854775808],
    /** ce */
    P0_longLit = [0, 0],
    P1_longLit = [1, 0];

  function update_progress(percent, cbn) {
    postMessage({
      action: action_progress,
      cbn: cbn,
      result: percent,
    });
  }

  function initDim(len) {
    ///NOTE: This is MUCH faster than "new Array(len)" in newer versions of v8 (starting with Node.js 0.11.15, which uses v8 3.28.73).
    var a = [];
    a[len - 1] = undefined;
    return a;
  }

  function add(a, b) {
    return create(a[0] + b[0], a[1] + b[1]);
  }

  /** cs */
  function and(a, b) {
    return makeFromBits(
      ~~Math.max(Math.min(a[1] / __4294967296, 2147483647), -2147483648) &
        ~~Math.max(Math.min(b[1] / __4294967296, 2147483647), -2147483648),
      lowBits_0(a) & lowBits_0(b),
    );
  }
  /** ce */

  function compare(a, b) {
    var nega, negb;
    if (a[0] == b[0] && a[1] == b[1]) {
      return 0;
    }
    nega = a[1] < 0;
    negb = b[1] < 0;
    if (nega && !negb) {
      return -1;
    }
    if (!nega && negb) {
      return 1;
    }
    if (sub(a, b)[1] < 0) {
      return -1;
    }
    return 1;
  }

  function create(valueLow, valueHigh) {
    var diffHigh, diffLow;
    valueHigh %= 1.8446744073709552e19;
    valueLow %= 1.8446744073709552e19;
    diffHigh = valueHigh % __4294967296;
    diffLow = Math.floor(valueLow / __4294967296) * __4294967296;
    valueHigh = valueHigh - diffHigh + diffLow;
    valueLow = valueLow - diffLow + diffHigh;
    while (valueLow < 0) {
      valueLow += __4294967296;
      valueHigh -= __4294967296;
    }
    while (valueLow > 4294967295) {
      valueLow -= __4294967296;
      valueHigh += __4294967296;
    }
    valueHigh = valueHigh % 1.8446744073709552e19;
    while (valueHigh > 9223372032559808512) {
      valueHigh -= 1.8446744073709552e19;
    }
    while (valueHigh < -9223372036854775808) {
      valueHigh += 1.8446744073709552e19;
    }
    return [valueLow, valueHigh];
  }

  /** cs */
  function eq(a, b) {
    return a[0] == b[0] && a[1] == b[1];
  }
  /** ce */
  function fromInt(value) {
    if (value >= 0) {
      return [value, 0];
    } else {
      return [value + __4294967296, -__4294967296];
    }
  }

  function lowBits_0(a) {
    if (a[0] >= 2147483648) {
      return ~~Math.max(Math.min(a[0] - __4294967296, 2147483647), -2147483648);
    } else {
      return ~~Math.max(Math.min(a[0], 2147483647), -2147483648);
    }
  }
  /** cs */
  function makeFromBits(highBits, lowBits) {
    var high, low;
    high = highBits * __4294967296;
    low = lowBits;
    if (lowBits < 0) {
      low += __4294967296;
    }
    return [low, high];
  }

  function pwrAsDouble(n) {
    if (n <= 30) {
      return 1 << n;
    } else {
      return pwrAsDouble(30) * pwrAsDouble(n - 30);
    }
  }

  function shl(a, n) {
    var diff, newHigh, newLow, twoToN;
    n &= 63;
    if (eq(a, MIN_VALUE)) {
      if (!n) {
        return a;
      }
      return P0_longLit;
    }
    if (a[1] < 0) {
      throw new Error('Neg');
    }
    twoToN = pwrAsDouble(n);
    newHigh = (a[1] * twoToN) % 1.8446744073709552e19;
    newLow = a[0] * twoToN;
    diff = newLow - (newLow % __4294967296);
    newHigh += diff;
    newLow -= diff;
    if (newHigh >= 9223372036854775807) {
      newHigh -= 1.8446744073709552e19;
    }
    return [newLow, newHigh];
  }

  function shr(a, n) {
    var shiftFact;
    n &= 63;
    shiftFact = pwrAsDouble(n);
    return create(Math.floor(a[0] / shiftFact), a[1] / shiftFact);
  }

  function shru(a, n) {
    var sr;
    n &= 63;
    sr = shr(a, n);
    if (a[1] < 0) {
      sr = add(sr, shl([2, 0], 63 - n));
    }
    return sr;
  }

  /** ce */

  function sub(a, b) {
    return create(a[0] - b[0], a[1] - b[1]);
  }

  function $ByteArrayInputStream(this$static, buf) {
    this$static.buf = buf;
    this$static.pos = 0;
    this$static.count = buf.length;
    return this$static;
  }

  /** ds */
  function $read(this$static) {
    if (this$static.pos >= this$static.count) return -1;
    return this$static.buf[this$static.pos++] & 255;
  }
  /** de */
  /** cs */
  function $read_0(this$static, buf, off, len) {
    if (this$static.pos >= this$static.count) return -1;
    len = Math.min(len, this$static.count - this$static.pos);
    arraycopy(this$static.buf, this$static.pos, buf, off, len);
    this$static.pos += len;
    return len;
  }
  /** ce */

  function $ByteArrayOutputStream(this$static) {
    this$static.buf = initDim(32);
    this$static.count = 0;
    return this$static;
  }

  function $toByteArray(this$static) {
    var data = this$static.buf;
    data.length = this$static.count;
    return data;
  }

  /** cs */
  function $write(this$static, b) {
    this$static.buf[this$static.count++] = (b << 24) >> 24;
  }
  /** ce */

  function $write_0(this$static, buf, off, len) {
    arraycopy(buf, off, this$static.buf, this$static.count, len);
    this$static.count += len;
  }

  /** cs */
  function $getChars(this$static, srcBegin, srcEnd, dst, dstBegin) {
    var srcIdx;
    for (srcIdx = srcBegin; srcIdx < srcEnd; ++srcIdx) {
      dst[dstBegin++] = this$static.charCodeAt(srcIdx);
    }
  }
  /** ce */

  function arraycopy(src, srcOfs, dest, destOfs, len) {
    for (var i = 0; i < len; ++i) {
      dest[destOfs + i] = src[srcOfs + i];
    }
  }

  /** cs */
  function $configure(this$static, encoder) {
    $SetDictionarySize_0(encoder, 1 << this$static.s);
    encoder._numFastBytes = this$static.f;
    $SetMatchFinder(encoder, this$static.m);

    /// lc is always 3
    /// lp is always 0
    /// pb is always 2
    encoder._numLiteralPosStateBits = 0;
    encoder._numLiteralContextBits = 3;
    encoder._posStateBits = 2;
    ///this$static._posStateMask = (1 << pb) - 1;
    encoder._posStateMask = 3;
  }

  function $init(this$static, input, output, length_0, mode) {
    var encoder, i;
    if (compare(length_0, N1_longLit) < 0) throw new Error('invalid length ' + length_0);
    this$static.length_0 = length_0;
    encoder = $Encoder({});
    $configure(mode, encoder);
    encoder._writeEndMark = typeof LZMA.disableEndMark == 'undefined';
    $WriteCoderProperties(encoder, output);
    for (i = 0; i < 64; i += 8) $write(output, lowBits_0(shr(length_0, i)) & 255);
    this$static.chunker = ((encoder._needReleaseMFStream = 0),
    ((encoder._inStream = input),
    (encoder._finished = 0),
    $Create_2(encoder),
    (encoder._rangeEncoder.Stream = output),
    $Init_4(encoder),
    $FillDistancesPrices(encoder),
    $FillAlignPrices(encoder),
    (encoder._lenEncoder._tableSize = encoder._numFastBytes + 1 - 2),
    $UpdateTables(encoder._lenEncoder, 1 << encoder._posStateBits),
    (encoder._repMatchLenEncoder._tableSize = encoder._numFastBytes + 1 - 2),
    $UpdateTables(encoder._repMatchLenEncoder, 1 << encoder._posStateBits),
    (encoder.nowPos64 = P0_longLit),
    undefined),
    $Chunker_0({}, encoder));
  }

  function $LZMAByteArrayCompressor(this$static, data, mode) {
    this$static.output = $ByteArrayOutputStream({});
    $init(this$static, $ByteArrayInputStream({}, data), this$static.output, fromInt(data.length), mode);
    return this$static;
  }
  /** ce */

  /** ds */
  function $init_0(this$static, input, output) {
    var decoder,
      hex_length = '',
      i,
      properties = [],
      r,
      tmp_length;

    for (i = 0; i < 5; ++i) {
      r = $read(input);
      if (r == -1) throw new Error('truncated input');
      properties[i] = (r << 24) >> 24;
    }

    decoder = $Decoder({});
    if (!$SetDecoderProperties(decoder, properties)) {
      throw new Error('corrupted input');
    }
    for (i = 0; i < 64; i += 8) {
      r = $read(input);
      if (r == -1) throw new Error('truncated input');
      r = r.toString(16);
      if (r.length == 1) r = '0' + r;
      hex_length = r + '' + hex_length;
    }

    /// Was the length set in the header (if it was compressed from a stream, the length is all f"s).
    if (/^0+$|^f+$/i.test(hex_length)) {
      /// The length is unknown, so set to -1.
      this$static.length_0 = N1_longLit;
    } else {
      ///NOTE: If there is a problem with the decoder because of the length, you can always set the length to -1 (N1_longLit) which means unknown.
      tmp_length = parseInt(hex_length, 16);
      /// If the length is too long to handle, just set it to unknown.
      if (tmp_length > 4294967295) {
        this$static.length_0 = N1_longLit;
      } else {
        this$static.length_0 = fromInt(tmp_length);
      }
    }

    this$static.chunker = $CodeInChunks(decoder, input, output, this$static.length_0);
  }

  function $LZMAByteArrayDecompressor(this$static, data) {
    this$static.output = $ByteArrayOutputStream({});
    $init_0(this$static, $ByteArrayInputStream({}, data), this$static.output);
    return this$static;
  }
  /** de */
  /** cs */
  function $Create_4(this$static, keepSizeBefore, keepSizeAfter, keepSizeReserv) {
    var blockSize;
    this$static._keepSizeBefore = keepSizeBefore;
    this$static._keepSizeAfter = keepSizeAfter;
    blockSize = keepSizeBefore + keepSizeAfter + keepSizeReserv;
    if (this$static._bufferBase == null || this$static._blockSize != blockSize) {
      this$static._bufferBase = null;
      this$static._blockSize = blockSize;
      this$static._bufferBase = initDim(this$static._blockSize);
    }
    this$static._pointerToLastSafePosition = this$static._blockSize - keepSizeAfter;
  }

  function $GetIndexByte(this$static, index) {
    return this$static._bufferBase[this$static._bufferOffset + this$static._pos + index];
  }

  function $GetMatchLen(this$static, index, distance, limit) {
    var i, pby;
    if (this$static._streamEndWasReached) {
      if (this$static._pos + index + limit > this$static._streamPos) {
        limit = this$static._streamPos - (this$static._pos + index);
      }
    }
    ++distance;
    pby = this$static._bufferOffset + this$static._pos + index;
    for (i = 0; i < limit && this$static._bufferBase[pby + i] == this$static._bufferBase[pby + i - distance]; ++i) {}
    return i;
  }

  function $GetNumAvailableBytes(this$static) {
    return this$static._streamPos - this$static._pos;
  }

  function $MoveBlock(this$static) {
    var i, numBytes, offset;
    offset = this$static._bufferOffset + this$static._pos - this$static._keepSizeBefore;
    if (offset > 0) {
      --offset;
    }
    numBytes = this$static._bufferOffset + this$static._streamPos - offset;
    for (i = 0; i < numBytes; ++i) {
      this$static._bufferBase[i] = this$static._bufferBase[offset + i];
    }
    this$static._bufferOffset -= offset;
  }

  function $MovePos_1(this$static) {
    var pointerToPostion;
    ++this$static._pos;
    if (this$static._pos > this$static._posLimit) {
      pointerToPostion = this$static._bufferOffset + this$static._pos;
      if (pointerToPostion > this$static._pointerToLastSafePosition) {
        $MoveBlock(this$static);
      }
      $ReadBlock(this$static);
    }
  }

  function $ReadBlock(this$static) {
    var numReadBytes, pointerToPostion, size;
    if (this$static._streamEndWasReached) return;
    while (1) {
      size = -this$static._bufferOffset + this$static._blockSize - this$static._streamPos;
      if (!size) return;
      numReadBytes = $read_0(
        this$static._stream,
        this$static._bufferBase,
        this$static._bufferOffset + this$static._streamPos,
        size,
      );
      if (numReadBytes == -1) {
        this$static._posLimit = this$static._streamPos;
        pointerToPostion = this$static._bufferOffset + this$static._posLimit;
        if (pointerToPostion > this$static._pointerToLastSafePosition) {
          this$static._posLimit = this$static._pointerToLastSafePosition - this$static._bufferOffset;
        }
        this$static._streamEndWasReached = 1;
        return;
      }
      this$static._streamPos += numReadBytes;
      if (this$static._streamPos >= this$static._pos + this$static._keepSizeAfter) {
        this$static._posLimit = this$static._streamPos - this$static._keepSizeAfter;
      }
    }
  }

  function $ReduceOffsets(this$static, subValue) {
    this$static._bufferOffset += subValue;
    this$static._posLimit -= subValue;
    this$static._pos -= subValue;
    this$static._streamPos -= subValue;
  }

  var CrcTable = (function() {
    var i,
      j,
      r,
      CrcTable = [];
    for (i = 0; i < 256; ++i) {
      r = i;
      for (j = 0; j < 8; ++j)
        if ((r & 1) != 0) {
          r = (r >>> 1) ^ -306674912;
        } else {
          r >>>= 1;
        }
      CrcTable[i] = r;
    }
    return CrcTable;
  })();

  function $Create_3(this$static, historySize, keepAddBufferBefore, matchMaxLen, keepAddBufferAfter) {
    var cyclicBufferSize, hs, windowReservSize;
    if (historySize < 1073741567) {
      this$static._cutValue = 16 + (matchMaxLen >> 1);
      windowReservSize = ~~((historySize + keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2) + 256;
      $Create_4(this$static, historySize + keepAddBufferBefore, matchMaxLen + keepAddBufferAfter, windowReservSize);
      this$static._matchMaxLen = matchMaxLen;
      cyclicBufferSize = historySize + 1;
      if (this$static._cyclicBufferSize != cyclicBufferSize) {
        this$static._son = initDim((this$static._cyclicBufferSize = cyclicBufferSize) * 2);
      }

      hs = 65536;
      if (this$static.HASH_ARRAY) {
        hs = historySize - 1;
        hs |= hs >> 1;
        hs |= hs >> 2;
        hs |= hs >> 4;
        hs |= hs >> 8;
        hs >>= 1;
        hs |= 65535;
        if (hs > 16777216) hs >>= 1;
        this$static._hashMask = hs;
        ++hs;
        hs += this$static.kFixHashSize;
      }

      if (hs != this$static._hashSizeSum) {
        this$static._hash = initDim((this$static._hashSizeSum = hs));
      }
    }
  }

  function $GetMatches(this$static, distances) {
    var count,
      cur,
      curMatch,
      curMatch2,
      curMatch3,
      cyclicPos,
      delta,
      hash2Value,
      hash3Value,
      hashValue,
      len,
      len0,
      len1,
      lenLimit,
      matchMinPos,
      maxLen,
      offset,
      pby1,
      ptr0,
      ptr1,
      temp;
    if (this$static._pos + this$static._matchMaxLen <= this$static._streamPos) {
      lenLimit = this$static._matchMaxLen;
    } else {
      lenLimit = this$static._streamPos - this$static._pos;
      if (lenLimit < this$static.kMinMatchCheck) {
        $MovePos_0(this$static);
        return 0;
      }
    }
    offset = 0;
    matchMinPos =
      this$static._pos > this$static._cyclicBufferSize ? this$static._pos - this$static._cyclicBufferSize : 0;
    cur = this$static._bufferOffset + this$static._pos;
    maxLen = 1;
    hash2Value = 0;
    hash3Value = 0;
    if (this$static.HASH_ARRAY) {
      temp = CrcTable[this$static._bufferBase[cur] & 255] ^ (this$static._bufferBase[cur + 1] & 255);
      hash2Value = temp & 1023;
      temp ^= (this$static._bufferBase[cur + 2] & 255) << 8;
      hash3Value = temp & 65535;
      hashValue = (temp ^ (CrcTable[this$static._bufferBase[cur + 3] & 255] << 5)) & this$static._hashMask;
    } else {
      hashValue = (this$static._bufferBase[cur] & 255) ^ ((this$static._bufferBase[cur + 1] & 255) << 8);
    }

    curMatch = this$static._hash[this$static.kFixHashSize + hashValue] || 0;
    if (this$static.HASH_ARRAY) {
      curMatch2 = this$static._hash[hash2Value] || 0;
      curMatch3 = this$static._hash[1024 + hash3Value] || 0;
      this$static._hash[hash2Value] = this$static._pos;
      this$static._hash[1024 + hash3Value] = this$static._pos;
      if (curMatch2 > matchMinPos) {
        if (this$static._bufferBase[this$static._bufferOffset + curMatch2] == this$static._bufferBase[cur]) {
          distances[offset++] = maxLen = 2;
          distances[offset++] = this$static._pos - curMatch2 - 1;
        }
      }
      if (curMatch3 > matchMinPos) {
        if (this$static._bufferBase[this$static._bufferOffset + curMatch3] == this$static._bufferBase[cur]) {
          if (curMatch3 == curMatch2) {
            offset -= 2;
          }
          distances[offset++] = maxLen = 3;
          distances[offset++] = this$static._pos - curMatch3 - 1;
          curMatch2 = curMatch3;
        }
      }
      if (offset != 0 && curMatch2 == curMatch) {
        offset -= 2;
        maxLen = 1;
      }
    }
    this$static._hash[this$static.kFixHashSize + hashValue] = this$static._pos;
    ptr0 = (this$static._cyclicBufferPos << 1) + 1;
    ptr1 = this$static._cyclicBufferPos << 1;
    len0 = len1 = this$static.kNumHashDirectBytes;
    if (this$static.kNumHashDirectBytes != 0) {
      if (curMatch > matchMinPos) {
        if (
          this$static._bufferBase[this$static._bufferOffset + curMatch + this$static.kNumHashDirectBytes] !=
          this$static._bufferBase[cur + this$static.kNumHashDirectBytes]
        ) {
          distances[offset++] = maxLen = this$static.kNumHashDirectBytes;
          distances[offset++] = this$static._pos - curMatch - 1;
        }
      }
    }
    count = this$static._cutValue;
    while (1) {
      if (curMatch <= matchMinPos || count-- == 0) {
        this$static._son[ptr0] = this$static._son[ptr1] = 0;
        break;
      }
      delta = this$static._pos - curMatch;
      cyclicPos =
        (delta <= this$static._cyclicBufferPos
          ? this$static._cyclicBufferPos - delta
          : this$static._cyclicBufferPos - delta + this$static._cyclicBufferSize) << 1;
      pby1 = this$static._bufferOffset + curMatch;
      len = len0 < len1 ? len0 : len1;
      if (this$static._bufferBase[pby1 + len] == this$static._bufferBase[cur + len]) {
        while (++len != lenLimit) {
          if (this$static._bufferBase[pby1 + len] != this$static._bufferBase[cur + len]) {
            break;
          }
        }
        if (maxLen < len) {
          distances[offset++] = maxLen = len;
          distances[offset++] = delta - 1;
          if (len == lenLimit) {
            this$static._son[ptr1] = this$static._son[cyclicPos];
            this$static._son[ptr0] = this$static._son[cyclicPos + 1];
            break;
          }
        }
      }
      if ((this$static._bufferBase[pby1 + len] & 255) < (this$static._bufferBase[cur + len] & 255)) {
        this$static._son[ptr1] = curMatch;
        ptr1 = cyclicPos + 1;
        curMatch = this$static._son[ptr1];
        len1 = len;
      } else {
        this$static._son[ptr0] = curMatch;
        ptr0 = cyclicPos;
        curMatch = this$static._son[ptr0];
        len0 = len;
      }
    }
    $MovePos_0(this$static);
    return offset;
  }

  function $Init_5(this$static) {
    this$static._bufferOffset = 0;
    this$static._pos = 0;
    this$static._streamPos = 0;
    this$static._streamEndWasReached = 0;
    $ReadBlock(this$static);
    this$static._cyclicBufferPos = 0;
    $ReduceOffsets(this$static, -1);
  }

  function $MovePos_0(this$static) {
    var subValue;
    if (++this$static._cyclicBufferPos >= this$static._cyclicBufferSize) {
      this$static._cyclicBufferPos = 0;
    }
    $MovePos_1(this$static);
    if (this$static._pos == 1073741823) {
      subValue = this$static._pos - this$static._cyclicBufferSize;
      $NormalizeLinks(this$static._son, this$static._cyclicBufferSize * 2, subValue);
      $NormalizeLinks(this$static._hash, this$static._hashSizeSum, subValue);
      $ReduceOffsets(this$static, subValue);
    }
  }

  ///NOTE: This is only called after reading one whole gigabyte.
  function $NormalizeLinks(items, numItems, subValue) {
    var i, value;
    for (i = 0; i < numItems; ++i) {
      value = items[i] || 0;
      if (value <= subValue) {
        value = 0;
      } else {
        value -= subValue;
      }
      items[i] = value;
    }
  }

  function $SetType(this$static, numHashBytes) {
    this$static.HASH_ARRAY = numHashBytes > 2;
    if (this$static.HASH_ARRAY) {
      this$static.kNumHashDirectBytes = 0;
      this$static.kMinMatchCheck = 4;
      this$static.kFixHashSize = 66560;
    } else {
      this$static.kNumHashDirectBytes = 2;
      this$static.kMinMatchCheck = 3;
      this$static.kFixHashSize = 0;
    }
  }

  function $Skip(this$static, num) {
    var count,
      cur,
      curMatch,
      cyclicPos,
      delta,
      hash2Value,
      hash3Value,
      hashValue,
      len,
      len0,
      len1,
      lenLimit,
      matchMinPos,
      pby1,
      ptr0,
      ptr1,
      temp;
    do {
      if (this$static._pos + this$static._matchMaxLen <= this$static._streamPos) {
        lenLimit = this$static._matchMaxLen;
      } else {
        lenLimit = this$static._streamPos - this$static._pos;
        if (lenLimit < this$static.kMinMatchCheck) {
          $MovePos_0(this$static);
          continue;
        }
      }
      matchMinPos =
        this$static._pos > this$static._cyclicBufferSize ? this$static._pos - this$static._cyclicBufferSize : 0;
      cur = this$static._bufferOffset + this$static._pos;
      if (this$static.HASH_ARRAY) {
        temp = CrcTable[this$static._bufferBase[cur] & 255] ^ (this$static._bufferBase[cur + 1] & 255);
        hash2Value = temp & 1023;
        this$static._hash[hash2Value] = this$static._pos;
        temp ^= (this$static._bufferBase[cur + 2] & 255) << 8;
        hash3Value = temp & 65535;
        this$static._hash[1024 + hash3Value] = this$static._pos;
        hashValue = (temp ^ (CrcTable[this$static._bufferBase[cur + 3] & 255] << 5)) & this$static._hashMask;
      } else {
        hashValue = (this$static._bufferBase[cur] & 255) ^ ((this$static._bufferBase[cur + 1] & 255) << 8);
      }
      curMatch = this$static._hash[this$static.kFixHashSize + hashValue];
      this$static._hash[this$static.kFixHashSize + hashValue] = this$static._pos;
      ptr0 = (this$static._cyclicBufferPos << 1) + 1;
      ptr1 = this$static._cyclicBufferPos << 1;
      len0 = len1 = this$static.kNumHashDirectBytes;
      count = this$static._cutValue;
      while (1) {
        if (curMatch <= matchMinPos || count-- == 0) {
          this$static._son[ptr0] = this$static._son[ptr1] = 0;
          break;
        }
        delta = this$static._pos - curMatch;
        cyclicPos =
          (delta <= this$static._cyclicBufferPos
            ? this$static._cyclicBufferPos - delta
            : this$static._cyclicBufferPos - delta + this$static._cyclicBufferSize) << 1;
        pby1 = this$static._bufferOffset + curMatch;
        len = len0 < len1 ? len0 : len1;
        if (this$static._bufferBase[pby1 + len] == this$static._bufferBase[cur + len]) {
          while (++len != lenLimit) {
            if (this$static._bufferBase[pby1 + len] != this$static._bufferBase[cur + len]) {
              break;
            }
          }
          if (len == lenLimit) {
            this$static._son[ptr1] = this$static._son[cyclicPos];
            this$static._son[ptr0] = this$static._son[cyclicPos + 1];
            break;
          }
        }
        if ((this$static._bufferBase[pby1 + len] & 255) < (this$static._bufferBase[cur + len] & 255)) {
          this$static._son[ptr1] = curMatch;
          ptr1 = cyclicPos + 1;
          curMatch = this$static._son[ptr1];
          len1 = len;
        } else {
          this$static._son[ptr0] = curMatch;
          ptr0 = cyclicPos;
          curMatch = this$static._son[ptr0];
          len0 = len;
        }
      }
      $MovePos_0(this$static);
    } while (--num != 0);
  }

  /** ce */
  /** ds */
  function $CopyBlock(this$static, distance, len) {
    var pos = this$static._pos - distance - 1;
    if (pos < 0) {
      pos += this$static._windowSize;
    }
    for (; len != 0; --len) {
      if (pos >= this$static._windowSize) {
        pos = 0;
      }
      this$static._buffer[this$static._pos++] = this$static._buffer[pos++];
      if (this$static._pos >= this$static._windowSize) {
        $Flush_0(this$static);
      }
    }
  }

  function $Create_5(this$static, windowSize) {
    if (this$static._buffer == null || this$static._windowSize != windowSize) {
      this$static._buffer = initDim(windowSize);
    }
    this$static._windowSize = windowSize;
    this$static._pos = 0;
    this$static._streamPos = 0;
  }

  function $Flush_0(this$static) {
    var size = this$static._pos - this$static._streamPos;
    if (!size) {
      return;
    }
    $write_0(this$static._stream, this$static._buffer, this$static._streamPos, size);
    if (this$static._pos >= this$static._windowSize) {
      this$static._pos = 0;
    }
    this$static._streamPos = this$static._pos;
  }

  function $GetByte(this$static, distance) {
    var pos = this$static._pos - distance - 1;
    if (pos < 0) {
      pos += this$static._windowSize;
    }
    return this$static._buffer[pos];
  }

  function $PutByte(this$static, b) {
    this$static._buffer[this$static._pos++] = b;
    if (this$static._pos >= this$static._windowSize) {
      $Flush_0(this$static);
    }
  }

  function $ReleaseStream(this$static) {
    $Flush_0(this$static);
    this$static._stream = null;
  }
  /** de */

  function GetLenToPosState(len) {
    len -= 2;
    if (len < 4) {
      return len;
    }
    return 3;
  }

  function StateUpdateChar(index) {
    if (index < 4) {
      return 0;
    }
    if (index < 10) {
      return index - 3;
    }
    return index - 6;
  }

  /** cs */
  function $Chunker_0(this$static, encoder) {
    this$static.encoder = encoder;
    this$static.decoder = null;
    this$static.alive = 1;
    return this$static;
  }
  /** ce */
  /** ds */
  function $Chunker(this$static, decoder) {
    this$static.decoder = decoder;
    this$static.encoder = null;
    this$static.alive = 1;
    return this$static;
  }
  /** de */

  function $processChunk(this$static) {
    if (!this$static.alive) {
      throw new Error('bad state');
    }

    if (this$static.encoder) {
      /// do:throw new Error("No encoding");
      /** cs */
      $processEncoderChunk(this$static);
      /** ce */
    } else {
      /// co:throw new Error("No decoding");
      /** ds */
      $processDecoderChunk(this$static);
      /** de */
    }
    return this$static.alive;
  }

  /** ds */
  function $processDecoderChunk(this$static) {
    var result = $CodeOneChunk(this$static.decoder);
    if (result == -1) {
      throw new Error('corrupted input');
    }
    this$static.inBytesProcessed = N1_longLit;
    this$static.outBytesProcessed = this$static.decoder.nowPos64;
    if (
      result ||
      (compare(this$static.decoder.outSize, P0_longLit) >= 0 &&
        compare(this$static.decoder.nowPos64, this$static.decoder.outSize) >= 0)
    ) {
      $Flush_0(this$static.decoder.m_OutWindow);
      $ReleaseStream(this$static.decoder.m_OutWindow);
      this$static.decoder.m_RangeDecoder.Stream = null;
      this$static.alive = 0;
    }
  }
  /** de */
  /** cs */
  function $processEncoderChunk(this$static) {
    $CodeOneBlock(
      this$static.encoder,
      this$static.encoder.processedInSize,
      this$static.encoder.processedOutSize,
      this$static.encoder.finished,
    );
    this$static.inBytesProcessed = this$static.encoder.processedInSize[0];
    if (this$static.encoder.finished[0]) {
      $ReleaseStreams(this$static.encoder);
      this$static.alive = 0;
    }
  }
  /** ce */

  /** ds */
  function $CodeInChunks(this$static, inStream, outStream, outSize) {
    this$static.m_RangeDecoder.Stream = inStream;
    $ReleaseStream(this$static.m_OutWindow);
    this$static.m_OutWindow._stream = outStream;
    $Init_1(this$static);
    this$static.state = 0;
    this$static.rep0 = 0;
    this$static.rep1 = 0;
    this$static.rep2 = 0;
    this$static.rep3 = 0;
    this$static.outSize = outSize;
    this$static.nowPos64 = P0_longLit;
    this$static.prevByte = 0;
    return $Chunker({}, this$static);
  }

  function $CodeOneChunk(this$static) {
    var decoder2, distance, len, numDirectBits, posSlot, posState;
    posState = lowBits_0(this$static.nowPos64) & this$static.m_PosStateMask;
    if (!$DecodeBit(this$static.m_RangeDecoder, this$static.m_IsMatchDecoders, (this$static.state << 4) + posState)) {
      decoder2 = $GetDecoder(this$static.m_LiteralDecoder, lowBits_0(this$static.nowPos64), this$static.prevByte);
      if (this$static.state < 7) {
        this$static.prevByte = $DecodeNormal(decoder2, this$static.m_RangeDecoder);
      } else {
        this$static.prevByte = $DecodeWithMatchByte(
          decoder2,
          this$static.m_RangeDecoder,
          $GetByte(this$static.m_OutWindow, this$static.rep0),
        );
      }
      $PutByte(this$static.m_OutWindow, this$static.prevByte);
      this$static.state = StateUpdateChar(this$static.state);
      this$static.nowPos64 = add(this$static.nowPos64, P1_longLit);
    } else {
      if ($DecodeBit(this$static.m_RangeDecoder, this$static.m_IsRepDecoders, this$static.state)) {
        len = 0;
        if (!$DecodeBit(this$static.m_RangeDecoder, this$static.m_IsRepG0Decoders, this$static.state)) {
          if (
            !$DecodeBit(
              this$static.m_RangeDecoder,
              this$static.m_IsRep0LongDecoders,
              (this$static.state << 4) + posState,
            )
          ) {
            this$static.state = this$static.state < 7 ? 9 : 11;
            len = 1;
          }
        } else {
          if (!$DecodeBit(this$static.m_RangeDecoder, this$static.m_IsRepG1Decoders, this$static.state)) {
            distance = this$static.rep1;
          } else {
            if (!$DecodeBit(this$static.m_RangeDecoder, this$static.m_IsRepG2Decoders, this$static.state)) {
              distance = this$static.rep2;
            } else {
              distance = this$static.rep3;
              this$static.rep3 = this$static.rep2;
            }
            this$static.rep2 = this$static.rep1;
          }
          this$static.rep1 = this$static.rep0;
          this$static.rep0 = distance;
        }
        if (!len) {
          len = $Decode(this$static.m_RepLenDecoder, this$static.m_RangeDecoder, posState) + 2;
          this$static.state = this$static.state < 7 ? 8 : 11;
        }
      } else {
        this$static.rep3 = this$static.rep2;
        this$static.rep2 = this$static.rep1;
        this$static.rep1 = this$static.rep0;
        len = 2 + $Decode(this$static.m_LenDecoder, this$static.m_RangeDecoder, posState);
        this$static.state = this$static.state < 7 ? 7 : 10;
        posSlot = $Decode_0(this$static.m_PosSlotDecoder[GetLenToPosState(len)], this$static.m_RangeDecoder);
        if (posSlot >= 4) {
          numDirectBits = (posSlot >> 1) - 1;
          this$static.rep0 = (2 | (posSlot & 1)) << numDirectBits;
          if (posSlot < 14) {
            this$static.rep0 += ReverseDecode(
              this$static.m_PosDecoders,
              this$static.rep0 - posSlot - 1,
              this$static.m_RangeDecoder,
              numDirectBits,
            );
          } else {
            this$static.rep0 += $DecodeDirectBits(this$static.m_RangeDecoder, numDirectBits - 4) << 4;
            this$static.rep0 += $ReverseDecode(this$static.m_PosAlignDecoder, this$static.m_RangeDecoder);
            if (this$static.rep0 < 0) {
              if (this$static.rep0 == -1) {
                return 1;
              }
              return -1;
            }
          }
        } else this$static.rep0 = posSlot;
      }
      if (
        compare(fromInt(this$static.rep0), this$static.nowPos64) >= 0 ||
        this$static.rep0 >= this$static.m_DictionarySizeCheck
      ) {
        return -1;
      }
      $CopyBlock(this$static.m_OutWindow, this$static.rep0, len);
      this$static.nowPos64 = add(this$static.nowPos64, fromInt(len));
      this$static.prevByte = $GetByte(this$static.m_OutWindow, 0);
    }
    return 0;
  }

  function $Decoder(this$static) {
    this$static.m_OutWindow = {};
    this$static.m_RangeDecoder = {};
    this$static.m_IsMatchDecoders = initDim(192);
    this$static.m_IsRepDecoders = initDim(12);
    this$static.m_IsRepG0Decoders = initDim(12);
    this$static.m_IsRepG1Decoders = initDim(12);
    this$static.m_IsRepG2Decoders = initDim(12);
    this$static.m_IsRep0LongDecoders = initDim(192);
    this$static.m_PosSlotDecoder = initDim(4);
    this$static.m_PosDecoders = initDim(114);
    this$static.m_PosAlignDecoder = $BitTreeDecoder({}, 4);
    this$static.m_LenDecoder = $Decoder$LenDecoder({});
    this$static.m_RepLenDecoder = $Decoder$LenDecoder({});
    this$static.m_LiteralDecoder = {};
    for (var i = 0; i < 4; ++i) {
      this$static.m_PosSlotDecoder[i] = $BitTreeDecoder({}, 6);
    }
    return this$static;
  }

  function $Init_1(this$static) {
    this$static.m_OutWindow._streamPos = 0;
    this$static.m_OutWindow._pos = 0;
    InitBitModels(this$static.m_IsMatchDecoders);
    InitBitModels(this$static.m_IsRep0LongDecoders);
    InitBitModels(this$static.m_IsRepDecoders);
    InitBitModels(this$static.m_IsRepG0Decoders);
    InitBitModels(this$static.m_IsRepG1Decoders);
    InitBitModels(this$static.m_IsRepG2Decoders);
    InitBitModels(this$static.m_PosDecoders);
    $Init_0(this$static.m_LiteralDecoder);
    for (var i = 0; i < 4; ++i) {
      InitBitModels(this$static.m_PosSlotDecoder[i].Models);
    }
    $Init(this$static.m_LenDecoder);
    $Init(this$static.m_RepLenDecoder);
    InitBitModels(this$static.m_PosAlignDecoder.Models);
    $Init_8(this$static.m_RangeDecoder);
  }

  function $SetDecoderProperties(this$static, properties) {
    var dictionarySize, i, lc, lp, pb, remainder, val;
    if (properties.length < 5) return 0;
    val = properties[0] & 255;
    lc = val % 9;
    remainder = ~~(val / 9);
    lp = remainder % 5;
    pb = ~~(remainder / 5);
    dictionarySize = 0;
    for (i = 0; i < 4; ++i) {
      dictionarySize += (properties[1 + i] & 255) << (i * 8);
    }
    ///NOTE: If the input is bad, it might call for an insanely large dictionary size, which would crash the script.
    if (dictionarySize > 99999999 || !$SetLcLpPb(this$static, lc, lp, pb)) {
      return 0;
    }
    return $SetDictionarySize(this$static, dictionarySize);
  }

  function $SetDictionarySize(this$static, dictionarySize) {
    if (dictionarySize < 0) {
      return 0;
    }
    if (this$static.m_DictionarySize != dictionarySize) {
      this$static.m_DictionarySize = dictionarySize;
      this$static.m_DictionarySizeCheck = Math.max(this$static.m_DictionarySize, 1);
      $Create_5(this$static.m_OutWindow, Math.max(this$static.m_DictionarySizeCheck, 4096));
    }
    return 1;
  }

  function $SetLcLpPb(this$static, lc, lp, pb) {
    if (lc > 8 || lp > 4 || pb > 4) {
      return 0;
    }
    $Create_0(this$static.m_LiteralDecoder, lp, lc);
    var numPosStates = 1 << pb;
    $Create(this$static.m_LenDecoder, numPosStates);
    $Create(this$static.m_RepLenDecoder, numPosStates);
    this$static.m_PosStateMask = numPosStates - 1;
    return 1;
  }

  function $Create(this$static, numPosStates) {
    for (; this$static.m_NumPosStates < numPosStates; ++this$static.m_NumPosStates) {
      this$static.m_LowCoder[this$static.m_NumPosStates] = $BitTreeDecoder({}, 3);
      this$static.m_MidCoder[this$static.m_NumPosStates] = $BitTreeDecoder({}, 3);
    }
  }

  function $Decode(this$static, rangeDecoder, posState) {
    if (!$DecodeBit(rangeDecoder, this$static.m_Choice, 0)) {
      return $Decode_0(this$static.m_LowCoder[posState], rangeDecoder);
    }
    var symbol = 8;
    if (!$DecodeBit(rangeDecoder, this$static.m_Choice, 1)) {
      symbol += $Decode_0(this$static.m_MidCoder[posState], rangeDecoder);
    } else {
      symbol += 8 + $Decode_0(this$static.m_HighCoder, rangeDecoder);
    }
    return symbol;
  }

  function $Decoder$LenDecoder(this$static) {
    this$static.m_Choice = initDim(2);
    this$static.m_LowCoder = initDim(16);
    this$static.m_MidCoder = initDim(16);
    this$static.m_HighCoder = $BitTreeDecoder({}, 8);
    this$static.m_NumPosStates = 0;
    return this$static;
  }

  function $Init(this$static) {
    InitBitModels(this$static.m_Choice);
    for (var posState = 0; posState < this$static.m_NumPosStates; ++posState) {
      InitBitModels(this$static.m_LowCoder[posState].Models);
      InitBitModels(this$static.m_MidCoder[posState].Models);
    }
    InitBitModels(this$static.m_HighCoder.Models);
  }

  function $Create_0(this$static, numPosBits, numPrevBits) {
    var i, numStates;
    if (
      this$static.m_Coders != null &&
      this$static.m_NumPrevBits == numPrevBits &&
      this$static.m_NumPosBits == numPosBits
    )
      return;
    this$static.m_NumPosBits = numPosBits;
    this$static.m_PosMask = (1 << numPosBits) - 1;
    this$static.m_NumPrevBits = numPrevBits;
    numStates = 1 << (this$static.m_NumPrevBits + this$static.m_NumPosBits);
    this$static.m_Coders = initDim(numStates);
    for (i = 0; i < numStates; ++i) this$static.m_Coders[i] = $Decoder$LiteralDecoder$Decoder2({});
  }

  function $GetDecoder(this$static, pos, prevByte) {
    return this$static.m_Coders[
      ((pos & this$static.m_PosMask) << this$static.m_NumPrevBits) +
        ((prevByte & 255) >>> (8 - this$static.m_NumPrevBits))
    ];
  }

  function $Init_0(this$static) {
    var i, numStates;
    numStates = 1 << (this$static.m_NumPrevBits + this$static.m_NumPosBits);
    for (i = 0; i < numStates; ++i) {
      InitBitModels(this$static.m_Coders[i].m_Decoders);
    }
  }

  function $DecodeNormal(this$static, rangeDecoder) {
    var symbol = 1;
    do {
      symbol = (symbol << 1) | $DecodeBit(rangeDecoder, this$static.m_Decoders, symbol);
    } while (symbol < 256);
    return (symbol << 24) >> 24;
  }

  function $DecodeWithMatchByte(this$static, rangeDecoder, matchByte) {
    var bit,
      matchBit,
      symbol = 1;
    do {
      matchBit = (matchByte >> 7) & 1;
      matchByte <<= 1;
      bit = $DecodeBit(rangeDecoder, this$static.m_Decoders, ((1 + matchBit) << 8) + symbol);
      symbol = (symbol << 1) | bit;
      if (matchBit != bit) {
        while (symbol < 256) {
          symbol = (symbol << 1) | $DecodeBit(rangeDecoder, this$static.m_Decoders, symbol);
        }
        break;
      }
    } while (symbol < 256);
    return (symbol << 24) >> 24;
  }

  function $Decoder$LiteralDecoder$Decoder2(this$static) {
    this$static.m_Decoders = initDim(768);
    return this$static;
  }

  /** de */
  /** cs */
  var g_FastPos = (function() {
    var j,
      k,
      slotFast,
      c = 2,
      g_FastPos = [0, 1];
    for (slotFast = 2; slotFast < 22; ++slotFast) {
      k = 1 << ((slotFast >> 1) - 1);
      for (j = 0; j < k; ++j, ++c) g_FastPos[c] = (slotFast << 24) >> 24;
    }
    return g_FastPos;
  })();

  function $Backward(this$static, cur) {
    var backCur, backMem, posMem, posPrev;
    this$static._optimumEndIndex = cur;
    posMem = this$static._optimum[cur].PosPrev;
    backMem = this$static._optimum[cur].BackPrev;
    do {
      if (this$static._optimum[cur].Prev1IsChar) {
        $MakeAsChar(this$static._optimum[posMem]);
        this$static._optimum[posMem].PosPrev = posMem - 1;
        if (this$static._optimum[cur].Prev2) {
          this$static._optimum[posMem - 1].Prev1IsChar = 0;
          this$static._optimum[posMem - 1].PosPrev = this$static._optimum[cur].PosPrev2;
          this$static._optimum[posMem - 1].BackPrev = this$static._optimum[cur].BackPrev2;
        }
      }
      posPrev = posMem;
      backCur = backMem;
      backMem = this$static._optimum[posPrev].BackPrev;
      posMem = this$static._optimum[posPrev].PosPrev;
      this$static._optimum[posPrev].BackPrev = backCur;
      this$static._optimum[posPrev].PosPrev = cur;
      cur = posPrev;
    } while (cur > 0);
    this$static.backRes = this$static._optimum[0].BackPrev;
    this$static._optimumCurrentIndex = this$static._optimum[0].PosPrev;
    return this$static._optimumCurrentIndex;
  }

  function $BaseInit(this$static) {
    this$static._state = 0;
    this$static._previousByte = 0;
    for (var i = 0; i < 4; ++i) {
      this$static._repDistances[i] = 0;
    }
  }

  function $CodeOneBlock(this$static, inSize, outSize, finished) {
    var baseVal,
      complexState,
      curByte,
      distance,
      footerBits,
      i,
      len,
      lenToPosState,
      matchByte,
      pos,
      posReduced,
      posSlot,
      posState,
      progressPosValuePrev,
      subCoder;
    inSize[0] = P0_longLit;
    outSize[0] = P0_longLit;
    finished[0] = 1;
    if (this$static._inStream) {
      this$static._matchFinder._stream = this$static._inStream;
      $Init_5(this$static._matchFinder);
      this$static._needReleaseMFStream = 1;
      this$static._inStream = null;
    }
    if (this$static._finished) {
      return;
    }
    this$static._finished = 1;
    progressPosValuePrev = this$static.nowPos64;
    if (eq(this$static.nowPos64, P0_longLit)) {
      if (!$GetNumAvailableBytes(this$static._matchFinder)) {
        $Flush(this$static, lowBits_0(this$static.nowPos64));
        return;
      }
      $ReadMatchDistances(this$static);
      posState = lowBits_0(this$static.nowPos64) & this$static._posStateMask;
      $Encode_3(this$static._rangeEncoder, this$static._isMatch, (this$static._state << 4) + posState, 0);
      this$static._state = StateUpdateChar(this$static._state);
      curByte = $GetIndexByte(this$static._matchFinder, -this$static._additionalOffset);
      $Encode_1(
        $GetSubCoder(this$static._literalEncoder, lowBits_0(this$static.nowPos64), this$static._previousByte),
        this$static._rangeEncoder,
        curByte,
      );
      this$static._previousByte = curByte;
      --this$static._additionalOffset;
      this$static.nowPos64 = add(this$static.nowPos64, P1_longLit);
    }
    if (!$GetNumAvailableBytes(this$static._matchFinder)) {
      $Flush(this$static, lowBits_0(this$static.nowPos64));
      return;
    }
    while (1) {
      len = $GetOptimum(this$static, lowBits_0(this$static.nowPos64));
      pos = this$static.backRes;
      posState = lowBits_0(this$static.nowPos64) & this$static._posStateMask;
      complexState = (this$static._state << 4) + posState;
      if (len == 1 && pos == -1) {
        $Encode_3(this$static._rangeEncoder, this$static._isMatch, complexState, 0);
        curByte = $GetIndexByte(this$static._matchFinder, -this$static._additionalOffset);
        subCoder = $GetSubCoder(
          this$static._literalEncoder,
          lowBits_0(this$static.nowPos64),
          this$static._previousByte,
        );
        if (this$static._state < 7) {
          $Encode_1(subCoder, this$static._rangeEncoder, curByte);
        } else {
          matchByte = $GetIndexByte(
            this$static._matchFinder,
            -this$static._repDistances[0] - 1 - this$static._additionalOffset,
          );
          $EncodeMatched(subCoder, this$static._rangeEncoder, matchByte, curByte);
        }
        this$static._previousByte = curByte;
        this$static._state = StateUpdateChar(this$static._state);
      } else {
        $Encode_3(this$static._rangeEncoder, this$static._isMatch, complexState, 1);
        if (pos < 4) {
          $Encode_3(this$static._rangeEncoder, this$static._isRep, this$static._state, 1);
          if (!pos) {
            $Encode_3(this$static._rangeEncoder, this$static._isRepG0, this$static._state, 0);
            if (len == 1) {
              $Encode_3(this$static._rangeEncoder, this$static._isRep0Long, complexState, 0);
            } else {
              $Encode_3(this$static._rangeEncoder, this$static._isRep0Long, complexState, 1);
            }
          } else {
            $Encode_3(this$static._rangeEncoder, this$static._isRepG0, this$static._state, 1);
            if (pos == 1) {
              $Encode_3(this$static._rangeEncoder, this$static._isRepG1, this$static._state, 0);
            } else {
              $Encode_3(this$static._rangeEncoder, this$static._isRepG1, this$static._state, 1);
              $Encode_3(this$static._rangeEncoder, this$static._isRepG2, this$static._state, pos - 2);
            }
          }
          if (len == 1) {
            this$static._state = this$static._state < 7 ? 9 : 11;
          } else {
            $Encode_0(this$static._repMatchLenEncoder, this$static._rangeEncoder, len - 2, posState);
            this$static._state = this$static._state < 7 ? 8 : 11;
          }
          distance = this$static._repDistances[pos];
          if (pos != 0) {
            for (i = pos; i >= 1; --i) {
              this$static._repDistances[i] = this$static._repDistances[i - 1];
            }
            this$static._repDistances[0] = distance;
          }
        } else {
          $Encode_3(this$static._rangeEncoder, this$static._isRep, this$static._state, 0);
          this$static._state = this$static._state < 7 ? 7 : 10;
          $Encode_0(this$static._lenEncoder, this$static._rangeEncoder, len - 2, posState);
          pos -= 4;
          posSlot = GetPosSlot(pos);
          lenToPosState = GetLenToPosState(len);
          $Encode_2(this$static._posSlotEncoder[lenToPosState], this$static._rangeEncoder, posSlot);
          if (posSlot >= 4) {
            footerBits = (posSlot >> 1) - 1;
            baseVal = (2 | (posSlot & 1)) << footerBits;
            posReduced = pos - baseVal;
            if (posSlot < 14) {
              ReverseEncode(
                this$static._posEncoders,
                baseVal - posSlot - 1,
                this$static._rangeEncoder,
                footerBits,
                posReduced,
              );
            } else {
              $EncodeDirectBits(this$static._rangeEncoder, posReduced >> 4, footerBits - 4);
              $ReverseEncode(this$static._posAlignEncoder, this$static._rangeEncoder, posReduced & 15);
              ++this$static._alignPriceCount;
            }
          }
          distance = pos;
          for (i = 3; i >= 1; --i) {
            this$static._repDistances[i] = this$static._repDistances[i - 1];
          }
          this$static._repDistances[0] = distance;
          ++this$static._matchPriceCount;
        }
        this$static._previousByte = $GetIndexByte(this$static._matchFinder, len - 1 - this$static._additionalOffset);
      }
      this$static._additionalOffset -= len;
      this$static.nowPos64 = add(this$static.nowPos64, fromInt(len));
      if (!this$static._additionalOffset) {
        if (this$static._matchPriceCount >= 128) {
          $FillDistancesPrices(this$static);
        }
        if (this$static._alignPriceCount >= 16) {
          $FillAlignPrices(this$static);
        }
        inSize[0] = this$static.nowPos64;
        outSize[0] = $GetProcessedSizeAdd(this$static._rangeEncoder);
        if (!$GetNumAvailableBytes(this$static._matchFinder)) {
          $Flush(this$static, lowBits_0(this$static.nowPos64));
          return;
        }
        if (compare(sub(this$static.nowPos64, progressPosValuePrev), [4096, 0]) >= 0) {
          this$static._finished = 0;
          finished[0] = 0;
          return;
        }
      }
    }
  }

  function $Create_2(this$static) {
    var bt, numHashBytes;
    if (!this$static._matchFinder) {
      bt = {};
      numHashBytes = 4;
      if (!this$static._matchFinderType) {
        numHashBytes = 2;
      }
      $SetType(bt, numHashBytes);
      this$static._matchFinder = bt;
    }
    $Create_1(this$static._literalEncoder, this$static._numLiteralPosStateBits, this$static._numLiteralContextBits);
    if (
      this$static._dictionarySize == this$static._dictionarySizePrev &&
      this$static._numFastBytesPrev == this$static._numFastBytes
    ) {
      return;
    }
    $Create_3(this$static._matchFinder, this$static._dictionarySize, 4096, this$static._numFastBytes, 274);
    this$static._dictionarySizePrev = this$static._dictionarySize;
    this$static._numFastBytesPrev = this$static._numFastBytes;
  }

  function $Encoder(this$static) {
    var i;
    this$static._repDistances = initDim(4);
    this$static._optimum = [];
    this$static._rangeEncoder = {};
    this$static._isMatch = initDim(192);
    this$static._isRep = initDim(12);
    this$static._isRepG0 = initDim(12);
    this$static._isRepG1 = initDim(12);
    this$static._isRepG2 = initDim(12);
    this$static._isRep0Long = initDim(192);
    this$static._posSlotEncoder = [];
    this$static._posEncoders = initDim(114);
    this$static._posAlignEncoder = $BitTreeEncoder({}, 4);
    this$static._lenEncoder = $Encoder$LenPriceTableEncoder({});
    this$static._repMatchLenEncoder = $Encoder$LenPriceTableEncoder({});
    this$static._literalEncoder = {};
    this$static._matchDistances = [];
    this$static._posSlotPrices = [];
    this$static._distancesPrices = [];
    this$static._alignPrices = initDim(16);
    this$static.reps = initDim(4);
    this$static.repLens = initDim(4);
    this$static.processedInSize = [P0_longLit];
    this$static.processedOutSize = [P0_longLit];
    this$static.finished = [0];
    this$static.properties = initDim(5);
    this$static.tempPrices = initDim(128);
    this$static._longestMatchLength = 0;
    this$static._matchFinderType = 1;
    this$static._numDistancePairs = 0;
    this$static._numFastBytesPrev = -1;
    this$static.backRes = 0;
    for (i = 0; i < 4096; ++i) {
      this$static._optimum[i] = {};
    }
    for (i = 0; i < 4; ++i) {
      this$static._posSlotEncoder[i] = $BitTreeEncoder({}, 6);
    }
    return this$static;
  }

  function $FillAlignPrices(this$static) {
    for (var i = 0; i < 16; ++i) {
      this$static._alignPrices[i] = $ReverseGetPrice(this$static._posAlignEncoder, i);
    }
    this$static._alignPriceCount = 0;
  }

  function $FillDistancesPrices(this$static) {
    var baseVal, encoder, footerBits, i, lenToPosState, posSlot, st, st2;
    for (i = 4; i < 128; ++i) {
      posSlot = GetPosSlot(i);
      footerBits = (posSlot >> 1) - 1;
      baseVal = (2 | (posSlot & 1)) << footerBits;
      this$static.tempPrices[i] = ReverseGetPrice(
        this$static._posEncoders,
        baseVal - posSlot - 1,
        footerBits,
        i - baseVal,
      );
    }
    for (lenToPosState = 0; lenToPosState < 4; ++lenToPosState) {
      encoder = this$static._posSlotEncoder[lenToPosState];
      st = lenToPosState << 6;
      for (posSlot = 0; posSlot < this$static._distTableSize; ++posSlot) {
        this$static._posSlotPrices[st + posSlot] = $GetPrice_1(encoder, posSlot);
      }
      for (posSlot = 14; posSlot < this$static._distTableSize; ++posSlot) {
        this$static._posSlotPrices[st + posSlot] += ((posSlot >> 1) - 1 - 4) << 6;
      }
      st2 = lenToPosState * 128;
      for (i = 0; i < 4; ++i) {
        this$static._distancesPrices[st2 + i] = this$static._posSlotPrices[st + i];
      }
      for (; i < 128; ++i) {
        this$static._distancesPrices[st2 + i] =
          this$static._posSlotPrices[st + GetPosSlot(i)] + this$static.tempPrices[i];
      }
    }
    this$static._matchPriceCount = 0;
  }

  function $Flush(this$static, nowPos) {
    $ReleaseMFStream(this$static);
    $WriteEndMarker(this$static, nowPos & this$static._posStateMask);
    for (var i = 0; i < 5; ++i) {
      $ShiftLow(this$static._rangeEncoder);
    }
  }

  function $GetOptimum(this$static, position) {
    var cur,
      curAnd1Price,
      curAndLenCharPrice,
      curAndLenPrice,
      curBack,
      curPrice,
      currentByte,
      distance,
      i,
      len,
      lenEnd,
      lenMain,
      lenRes,
      lenTest,
      lenTest2,
      lenTestTemp,
      matchByte,
      matchPrice,
      newLen,
      nextIsChar,
      nextMatchPrice,
      nextOptimum,
      nextRepMatchPrice,
      normalMatchPrice,
      numAvailableBytes,
      numAvailableBytesFull,
      numDistancePairs,
      offs,
      offset,
      opt,
      optimum,
      pos,
      posPrev,
      posState,
      posStateNext,
      price_4,
      repIndex,
      repLen,
      repMatchPrice,
      repMaxIndex,
      shortRepPrice,
      startLen,
      state,
      state2,
      t,
      price,
      price_0,
      price_1,
      price_2,
      price_3;
    if (this$static._optimumEndIndex != this$static._optimumCurrentIndex) {
      lenRes = this$static._optimum[this$static._optimumCurrentIndex].PosPrev - this$static._optimumCurrentIndex;
      this$static.backRes = this$static._optimum[this$static._optimumCurrentIndex].BackPrev;
      this$static._optimumCurrentIndex = this$static._optimum[this$static._optimumCurrentIndex].PosPrev;
      return lenRes;
    }
    this$static._optimumCurrentIndex = this$static._optimumEndIndex = 0;
    if (this$static._longestMatchWasFound) {
      lenMain = this$static._longestMatchLength;
      this$static._longestMatchWasFound = 0;
    } else {
      lenMain = $ReadMatchDistances(this$static);
    }
    numDistancePairs = this$static._numDistancePairs;
    numAvailableBytes = $GetNumAvailableBytes(this$static._matchFinder) + 1;
    if (numAvailableBytes < 2) {
      this$static.backRes = -1;
      return 1;
    }
    if (numAvailableBytes > 273) {
      numAvailableBytes = 273;
    }
    repMaxIndex = 0;
    for (i = 0; i < 4; ++i) {
      this$static.reps[i] = this$static._repDistances[i];
      this$static.repLens[i] = $GetMatchLen(this$static._matchFinder, -1, this$static.reps[i], 273);
      if (this$static.repLens[i] > this$static.repLens[repMaxIndex]) {
        repMaxIndex = i;
      }
    }
    if (this$static.repLens[repMaxIndex] >= this$static._numFastBytes) {
      this$static.backRes = repMaxIndex;
      lenRes = this$static.repLens[repMaxIndex];
      $MovePos(this$static, lenRes - 1);
      return lenRes;
    }
    if (lenMain >= this$static._numFastBytes) {
      this$static.backRes = this$static._matchDistances[numDistancePairs - 1] + 4;
      $MovePos(this$static, lenMain - 1);
      return lenMain;
    }
    currentByte = $GetIndexByte(this$static._matchFinder, -1);
    matchByte = $GetIndexByte(this$static._matchFinder, -this$static._repDistances[0] - 1 - 1);
    if (lenMain < 2 && currentByte != matchByte && this$static.repLens[repMaxIndex] < 2) {
      this$static.backRes = -1;
      return 1;
    }
    this$static._optimum[0].State = this$static._state;
    posState = position & this$static._posStateMask;
    this$static._optimum[1].Price =
      ProbPrices[this$static._isMatch[(this$static._state << 4) + posState] >>> 2] +
      $GetPrice_0(
        $GetSubCoder(this$static._literalEncoder, position, this$static._previousByte),
        this$static._state >= 7,
        matchByte,
        currentByte,
      );
    $MakeAsChar(this$static._optimum[1]);
    matchPrice = ProbPrices[(2048 - this$static._isMatch[(this$static._state << 4) + posState]) >>> 2];
    repMatchPrice = matchPrice + ProbPrices[(2048 - this$static._isRep[this$static._state]) >>> 2];
    if (matchByte == currentByte) {
      shortRepPrice = repMatchPrice + $GetRepLen1Price(this$static, this$static._state, posState);
      if (shortRepPrice < this$static._optimum[1].Price) {
        this$static._optimum[1].Price = shortRepPrice;
        $MakeAsShortRep(this$static._optimum[1]);
      }
    }
    lenEnd = lenMain >= this$static.repLens[repMaxIndex] ? lenMain : this$static.repLens[repMaxIndex];
    if (lenEnd < 2) {
      this$static.backRes = this$static._optimum[1].BackPrev;
      return 1;
    }
    this$static._optimum[1].PosPrev = 0;
    this$static._optimum[0].Backs0 = this$static.reps[0];
    this$static._optimum[0].Backs1 = this$static.reps[1];
    this$static._optimum[0].Backs2 = this$static.reps[2];
    this$static._optimum[0].Backs3 = this$static.reps[3];
    len = lenEnd;
    do {
      this$static._optimum[len--].Price = 268435455;
    } while (len >= 2);
    for (i = 0; i < 4; ++i) {
      repLen = this$static.repLens[i];
      if (repLen < 2) {
        continue;
      }
      price_4 = repMatchPrice + $GetPureRepPrice(this$static, i, this$static._state, posState);
      do {
        curAndLenPrice = price_4 + $GetPrice(this$static._repMatchLenEncoder, repLen - 2, posState);
        optimum = this$static._optimum[repLen];
        if (curAndLenPrice < optimum.Price) {
          optimum.Price = curAndLenPrice;
          optimum.PosPrev = 0;
          optimum.BackPrev = i;
          optimum.Prev1IsChar = 0;
        }
      } while (--repLen >= 2);
    }
    normalMatchPrice = matchPrice + ProbPrices[this$static._isRep[this$static._state] >>> 2];
    len = this$static.repLens[0] >= 2 ? this$static.repLens[0] + 1 : 2;
    if (len <= lenMain) {
      offs = 0;
      while (len > this$static._matchDistances[offs]) {
        offs += 2;
      }
      for (; ; ++len) {
        distance = this$static._matchDistances[offs + 1];
        curAndLenPrice = normalMatchPrice + $GetPosLenPrice(this$static, distance, len, posState);
        optimum = this$static._optimum[len];
        if (curAndLenPrice < optimum.Price) {
          optimum.Price = curAndLenPrice;
          optimum.PosPrev = 0;
          optimum.BackPrev = distance + 4;
          optimum.Prev1IsChar = 0;
        }
        if (len == this$static._matchDistances[offs]) {
          offs += 2;
          if (offs == numDistancePairs) {
            break;
          }
        }
      }
    }
    cur = 0;
    while (1) {
      ++cur;
      if (cur == lenEnd) {
        return $Backward(this$static, cur);
      }
      newLen = $ReadMatchDistances(this$static);
      numDistancePairs = this$static._numDistancePairs;
      if (newLen >= this$static._numFastBytes) {
        this$static._longestMatchLength = newLen;
        this$static._longestMatchWasFound = 1;
        return $Backward(this$static, cur);
      }
      ++position;
      posPrev = this$static._optimum[cur].PosPrev;
      if (this$static._optimum[cur].Prev1IsChar) {
        --posPrev;
        if (this$static._optimum[cur].Prev2) {
          state = this$static._optimum[this$static._optimum[cur].PosPrev2].State;
          if (this$static._optimum[cur].BackPrev2 < 4) {
            state = state < 7 ? 8 : 11;
          } else {
            state = state < 7 ? 7 : 10;
          }
        } else {
          state = this$static._optimum[posPrev].State;
        }
        state = StateUpdateChar(state);
      } else {
        state = this$static._optimum[posPrev].State;
      }
      if (posPrev == cur - 1) {
        if (!this$static._optimum[cur].BackPrev) {
          state = state < 7 ? 9 : 11;
        } else {
          state = StateUpdateChar(state);
        }
      } else {
        if (this$static._optimum[cur].Prev1IsChar && this$static._optimum[cur].Prev2) {
          posPrev = this$static._optimum[cur].PosPrev2;
          pos = this$static._optimum[cur].BackPrev2;
          state = state < 7 ? 8 : 11;
        } else {
          pos = this$static._optimum[cur].BackPrev;
          if (pos < 4) {
            state = state < 7 ? 8 : 11;
          } else {
            state = state < 7 ? 7 : 10;
          }
        }
        opt = this$static._optimum[posPrev];
        if (pos < 4) {
          if (!pos) {
            this$static.reps[0] = opt.Backs0;
            this$static.reps[1] = opt.Backs1;
            this$static.reps[2] = opt.Backs2;
            this$static.reps[3] = opt.Backs3;
          } else if (pos == 1) {
            this$static.reps[0] = opt.Backs1;
            this$static.reps[1] = opt.Backs0;
            this$static.reps[2] = opt.Backs2;
            this$static.reps[3] = opt.Backs3;
          } else if (pos == 2) {
            this$static.reps[0] = opt.Backs2;
            this$static.reps[1] = opt.Backs0;
            this$static.reps[2] = opt.Backs1;
            this$static.reps[3] = opt.Backs3;
          } else {
            this$static.reps[0] = opt.Backs3;
            this$static.reps[1] = opt.Backs0;
            this$static.reps[2] = opt.Backs1;
            this$static.reps[3] = opt.Backs2;
          }
        } else {
          this$static.reps[0] = pos - 4;
          this$static.reps[1] = opt.Backs0;
          this$static.reps[2] = opt.Backs1;
          this$static.reps[3] = opt.Backs2;
        }
      }
      this$static._optimum[cur].State = state;
      this$static._optimum[cur].Backs0 = this$static.reps[0];
      this$static._optimum[cur].Backs1 = this$static.reps[1];
      this$static._optimum[cur].Backs2 = this$static.reps[2];
      this$static._optimum[cur].Backs3 = this$static.reps[3];
      curPrice = this$static._optimum[cur].Price;
      currentByte = $GetIndexByte(this$static._matchFinder, -1);
      matchByte = $GetIndexByte(this$static._matchFinder, -this$static.reps[0] - 1 - 1);
      posState = position & this$static._posStateMask;
      curAnd1Price =
        curPrice +
        ProbPrices[this$static._isMatch[(state << 4) + posState] >>> 2] +
        $GetPrice_0(
          $GetSubCoder(this$static._literalEncoder, position, $GetIndexByte(this$static._matchFinder, -2)),
          state >= 7,
          matchByte,
          currentByte,
        );
      nextOptimum = this$static._optimum[cur + 1];
      nextIsChar = 0;
      if (curAnd1Price < nextOptimum.Price) {
        nextOptimum.Price = curAnd1Price;
        nextOptimum.PosPrev = cur;
        nextOptimum.BackPrev = -1;
        nextOptimum.Prev1IsChar = 0;
        nextIsChar = 1;
      }
      matchPrice = curPrice + ProbPrices[(2048 - this$static._isMatch[(state << 4) + posState]) >>> 2];
      repMatchPrice = matchPrice + ProbPrices[(2048 - this$static._isRep[state]) >>> 2];
      if (matchByte == currentByte && !(nextOptimum.PosPrev < cur && !nextOptimum.BackPrev)) {
        shortRepPrice =
          repMatchPrice +
          (ProbPrices[this$static._isRepG0[state] >>> 2] +
            ProbPrices[this$static._isRep0Long[(state << 4) + posState] >>> 2]);
        if (shortRepPrice <= nextOptimum.Price) {
          nextOptimum.Price = shortRepPrice;
          nextOptimum.PosPrev = cur;
          nextOptimum.BackPrev = 0;
          nextOptimum.Prev1IsChar = 0;
          nextIsChar = 1;
        }
      }
      numAvailableBytesFull = $GetNumAvailableBytes(this$static._matchFinder) + 1;
      numAvailableBytesFull = 4095 - cur < numAvailableBytesFull ? 4095 - cur : numAvailableBytesFull;
      numAvailableBytes = numAvailableBytesFull;
      if (numAvailableBytes < 2) {
        continue;
      }
      if (numAvailableBytes > this$static._numFastBytes) {
        numAvailableBytes = this$static._numFastBytes;
      }
      if (!nextIsChar && matchByte != currentByte) {
        t = Math.min(numAvailableBytesFull - 1, this$static._numFastBytes);
        lenTest2 = $GetMatchLen(this$static._matchFinder, 0, this$static.reps[0], t);
        if (lenTest2 >= 2) {
          state2 = StateUpdateChar(state);
          posStateNext = (position + 1) & this$static._posStateMask;
          nextRepMatchPrice =
            curAnd1Price +
            ProbPrices[(2048 - this$static._isMatch[(state2 << 4) + posStateNext]) >>> 2] +
            ProbPrices[(2048 - this$static._isRep[state2]) >>> 2];
          offset = cur + 1 + lenTest2;
          while (lenEnd < offset) {
            this$static._optimum[++lenEnd].Price = 268435455;
          }
          curAndLenPrice =
            nextRepMatchPrice +
            ((price = $GetPrice(this$static._repMatchLenEncoder, lenTest2 - 2, posStateNext)),
            price + $GetPureRepPrice(this$static, 0, state2, posStateNext));
          optimum = this$static._optimum[offset];
          if (curAndLenPrice < optimum.Price) {
            optimum.Price = curAndLenPrice;
            optimum.PosPrev = cur + 1;
            optimum.BackPrev = 0;
            optimum.Prev1IsChar = 1;
            optimum.Prev2 = 0;
          }
        }
      }
      startLen = 2;
      for (repIndex = 0; repIndex < 4; ++repIndex) {
        lenTest = $GetMatchLen(this$static._matchFinder, -1, this$static.reps[repIndex], numAvailableBytes);
        if (lenTest < 2) {
          continue;
        }
        lenTestTemp = lenTest;
        do {
          while (lenEnd < cur + lenTest) {
            this$static._optimum[++lenEnd].Price = 268435455;
          }
          curAndLenPrice =
            repMatchPrice +
            ((price_0 = $GetPrice(this$static._repMatchLenEncoder, lenTest - 2, posState)),
            price_0 + $GetPureRepPrice(this$static, repIndex, state, posState));
          optimum = this$static._optimum[cur + lenTest];
          if (curAndLenPrice < optimum.Price) {
            optimum.Price = curAndLenPrice;
            optimum.PosPrev = cur;
            optimum.BackPrev = repIndex;
            optimum.Prev1IsChar = 0;
          }
        } while (--lenTest >= 2);
        lenTest = lenTestTemp;
        if (!repIndex) {
          startLen = lenTest + 1;
        }
        if (lenTest < numAvailableBytesFull) {
          t = Math.min(numAvailableBytesFull - 1 - lenTest, this$static._numFastBytes);
          lenTest2 = $GetMatchLen(this$static._matchFinder, lenTest, this$static.reps[repIndex], t);
          if (lenTest2 >= 2) {
            state2 = state < 7 ? 8 : 11;
            posStateNext = (position + lenTest) & this$static._posStateMask;
            curAndLenCharPrice =
              repMatchPrice +
              ((price_1 = $GetPrice(this$static._repMatchLenEncoder, lenTest - 2, posState)),
              price_1 + $GetPureRepPrice(this$static, repIndex, state, posState)) +
              ProbPrices[this$static._isMatch[(state2 << 4) + posStateNext] >>> 2] +
              $GetPrice_0(
                $GetSubCoder(
                  this$static._literalEncoder,
                  position + lenTest,
                  $GetIndexByte(this$static._matchFinder, lenTest - 1 - 1),
                ),
                1,
                $GetIndexByte(this$static._matchFinder, lenTest - 1 - (this$static.reps[repIndex] + 1)),
                $GetIndexByte(this$static._matchFinder, lenTest - 1),
              );
            state2 = StateUpdateChar(state2);
            posStateNext = (position + lenTest + 1) & this$static._posStateMask;
            nextMatchPrice =
              curAndLenCharPrice + ProbPrices[(2048 - this$static._isMatch[(state2 << 4) + posStateNext]) >>> 2];
            nextRepMatchPrice = nextMatchPrice + ProbPrices[(2048 - this$static._isRep[state2]) >>> 2];
            offset = lenTest + 1 + lenTest2;
            while (lenEnd < cur + offset) {
              this$static._optimum[++lenEnd].Price = 268435455;
            }
            curAndLenPrice =
              nextRepMatchPrice +
              ((price_2 = $GetPrice(this$static._repMatchLenEncoder, lenTest2 - 2, posStateNext)),
              price_2 + $GetPureRepPrice(this$static, 0, state2, posStateNext));
            optimum = this$static._optimum[cur + offset];
            if (curAndLenPrice < optimum.Price) {
              optimum.Price = curAndLenPrice;
              optimum.PosPrev = cur + lenTest + 1;
              optimum.BackPrev = 0;
              optimum.Prev1IsChar = 1;
              optimum.Prev2 = 1;
              optimum.PosPrev2 = cur;
              optimum.BackPrev2 = repIndex;
            }
          }
        }
      }
      if (newLen > numAvailableBytes) {
        newLen = numAvailableBytes;
        for (numDistancePairs = 0; newLen > this$static._matchDistances[numDistancePairs]; numDistancePairs += 2) {}
        this$static._matchDistances[numDistancePairs] = newLen;
        numDistancePairs += 2;
      }
      if (newLen >= startLen) {
        normalMatchPrice = matchPrice + ProbPrices[this$static._isRep[state] >>> 2];
        while (lenEnd < cur + newLen) {
          this$static._optimum[++lenEnd].Price = 268435455;
        }
        offs = 0;
        while (startLen > this$static._matchDistances[offs]) {
          offs += 2;
        }
        for (lenTest = startLen; ; ++lenTest) {
          curBack = this$static._matchDistances[offs + 1];
          curAndLenPrice = normalMatchPrice + $GetPosLenPrice(this$static, curBack, lenTest, posState);
          optimum = this$static._optimum[cur + lenTest];
          if (curAndLenPrice < optimum.Price) {
            optimum.Price = curAndLenPrice;
            optimum.PosPrev = cur;
            optimum.BackPrev = curBack + 4;
            optimum.Prev1IsChar = 0;
          }
          if (lenTest == this$static._matchDistances[offs]) {
            if (lenTest < numAvailableBytesFull) {
              t = Math.min(numAvailableBytesFull - 1 - lenTest, this$static._numFastBytes);
              lenTest2 = $GetMatchLen(this$static._matchFinder, lenTest, curBack, t);
              if (lenTest2 >= 2) {
                state2 = state < 7 ? 7 : 10;
                posStateNext = (position + lenTest) & this$static._posStateMask;
                curAndLenCharPrice =
                  curAndLenPrice +
                  ProbPrices[this$static._isMatch[(state2 << 4) + posStateNext] >>> 2] +
                  $GetPrice_0(
                    $GetSubCoder(
                      this$static._literalEncoder,
                      position + lenTest,
                      $GetIndexByte(this$static._matchFinder, lenTest - 1 - 1),
                    ),
                    1,
                    $GetIndexByte(this$static._matchFinder, lenTest - (curBack + 1) - 1),
                    $GetIndexByte(this$static._matchFinder, lenTest - 1),
                  );
                state2 = StateUpdateChar(state2);
                posStateNext = (position + lenTest + 1) & this$static._posStateMask;
                nextMatchPrice =
                  curAndLenCharPrice + ProbPrices[(2048 - this$static._isMatch[(state2 << 4) + posStateNext]) >>> 2];
                nextRepMatchPrice = nextMatchPrice + ProbPrices[(2048 - this$static._isRep[state2]) >>> 2];
                offset = lenTest + 1 + lenTest2;
                while (lenEnd < cur + offset) {
                  this$static._optimum[++lenEnd].Price = 268435455;
                }
                curAndLenPrice =
                  nextRepMatchPrice +
                  ((price_3 = $GetPrice(this$static._repMatchLenEncoder, lenTest2 - 2, posStateNext)),
                  price_3 + $GetPureRepPrice(this$static, 0, state2, posStateNext));
                optimum = this$static._optimum[cur + offset];
                if (curAndLenPrice < optimum.Price) {
                  optimum.Price = curAndLenPrice;
                  optimum.PosPrev = cur + lenTest + 1;
                  optimum.BackPrev = 0;
                  optimum.Prev1IsChar = 1;
                  optimum.Prev2 = 1;
                  optimum.PosPrev2 = cur;
                  optimum.BackPrev2 = curBack + 4;
                }
              }
            }
            offs += 2;
            if (offs == numDistancePairs) break;
          }
        }
      }
    }
  }

  function $GetPosLenPrice(this$static, pos, len, posState) {
    var price,
      lenToPosState = GetLenToPosState(len);
    if (pos < 128) {
      price = this$static._distancesPrices[lenToPosState * 128 + pos];
    } else {
      price = this$static._posSlotPrices[(lenToPosState << 6) + GetPosSlot2(pos)] + this$static._alignPrices[pos & 15];
    }
    return price + $GetPrice(this$static._lenEncoder, len - 2, posState);
  }

  function $GetPureRepPrice(this$static, repIndex, state, posState) {
    var price;
    if (!repIndex) {
      price = ProbPrices[this$static._isRepG0[state] >>> 2];
      price += ProbPrices[(2048 - this$static._isRep0Long[(state << 4) + posState]) >>> 2];
    } else {
      price = ProbPrices[(2048 - this$static._isRepG0[state]) >>> 2];
      if (repIndex == 1) {
        price += ProbPrices[this$static._isRepG1[state] >>> 2];
      } else {
        price += ProbPrices[(2048 - this$static._isRepG1[state]) >>> 2];
        price += GetPrice(this$static._isRepG2[state], repIndex - 2);
      }
    }
    return price;
  }

  function $GetRepLen1Price(this$static, state, posState) {
    return (
      ProbPrices[this$static._isRepG0[state] >>> 2] + ProbPrices[this$static._isRep0Long[(state << 4) + posState] >>> 2]
    );
  }

  function $Init_4(this$static) {
    $BaseInit(this$static);
    $Init_9(this$static._rangeEncoder);
    InitBitModels(this$static._isMatch);
    InitBitModels(this$static._isRep0Long);
    InitBitModels(this$static._isRep);
    InitBitModels(this$static._isRepG0);
    InitBitModels(this$static._isRepG1);
    InitBitModels(this$static._isRepG2);
    InitBitModels(this$static._posEncoders);
    $Init_3(this$static._literalEncoder);
    for (var i = 0; i < 4; ++i) {
      InitBitModels(this$static._posSlotEncoder[i].Models);
    }
    $Init_2(this$static._lenEncoder, 1 << this$static._posStateBits);
    $Init_2(this$static._repMatchLenEncoder, 1 << this$static._posStateBits);
    InitBitModels(this$static._posAlignEncoder.Models);
    this$static._longestMatchWasFound = 0;
    this$static._optimumEndIndex = 0;
    this$static._optimumCurrentIndex = 0;
    this$static._additionalOffset = 0;
  }

  function $MovePos(this$static, num) {
    if (num > 0) {
      $Skip(this$static._matchFinder, num);
      this$static._additionalOffset += num;
    }
  }

  function $ReadMatchDistances(this$static) {
    var lenRes = 0;
    this$static._numDistancePairs = $GetMatches(this$static._matchFinder, this$static._matchDistances);
    if (this$static._numDistancePairs > 0) {
      lenRes = this$static._matchDistances[this$static._numDistancePairs - 2];
      if (lenRes == this$static._numFastBytes)
        lenRes += $GetMatchLen(
          this$static._matchFinder,
          lenRes - 1,
          this$static._matchDistances[this$static._numDistancePairs - 1],
          273 - lenRes,
        );
    }
    ++this$static._additionalOffset;
    return lenRes;
  }

  function $ReleaseMFStream(this$static) {
    if (this$static._matchFinder && this$static._needReleaseMFStream) {
      this$static._matchFinder._stream = null;
      this$static._needReleaseMFStream = 0;
    }
  }

  function $ReleaseStreams(this$static) {
    $ReleaseMFStream(this$static);
    this$static._rangeEncoder.Stream = null;
  }

  function $SetDictionarySize_0(this$static, dictionarySize) {
    this$static._dictionarySize = dictionarySize;
    for (var dicLogSize = 0; dictionarySize > 1 << dicLogSize; ++dicLogSize) {}
    this$static._distTableSize = dicLogSize * 2;
  }

  function $SetMatchFinder(this$static, matchFinderIndex) {
    var matchFinderIndexPrev = this$static._matchFinderType;
    this$static._matchFinderType = matchFinderIndex;
    if (this$static._matchFinder && matchFinderIndexPrev != this$static._matchFinderType) {
      this$static._dictionarySizePrev = -1;
      this$static._matchFinder = null;
    }
  }

  function $WriteCoderProperties(this$static, outStream) {
    this$static.properties[0] =
      (((this$static._posStateBits * 5 + this$static._numLiteralPosStateBits) * 9 +
        this$static._numLiteralContextBits) <<
        24) >>
      24;
    for (var i = 0; i < 4; ++i) {
      this$static.properties[1 + i] = ((this$static._dictionarySize >> (8 * i)) << 24) >> 24;
    }
    $write_0(outStream, this$static.properties, 0, 5);
  }

  function $WriteEndMarker(this$static, posState) {
    if (!this$static._writeEndMark) {
      return;
    }
    $Encode_3(this$static._rangeEncoder, this$static._isMatch, (this$static._state << 4) + posState, 1);
    $Encode_3(this$static._rangeEncoder, this$static._isRep, this$static._state, 0);
    this$static._state = this$static._state < 7 ? 7 : 10;
    $Encode_0(this$static._lenEncoder, this$static._rangeEncoder, 0, posState);
    var lenToPosState = GetLenToPosState(2);
    $Encode_2(this$static._posSlotEncoder[lenToPosState], this$static._rangeEncoder, 63);
    $EncodeDirectBits(this$static._rangeEncoder, 67108863, 26);
    $ReverseEncode(this$static._posAlignEncoder, this$static._rangeEncoder, 15);
  }

  function GetPosSlot(pos) {
    if (pos < 2048) {
      return g_FastPos[pos];
    }
    if (pos < 2097152) {
      return g_FastPos[pos >> 10] + 20;
    }
    return g_FastPos[pos >> 20] + 40;
  }

  function GetPosSlot2(pos) {
    if (pos < 131072) {
      return g_FastPos[pos >> 6] + 12;
    }
    if (pos < 134217728) {
      return g_FastPos[pos >> 16] + 32;
    }
    return g_FastPos[pos >> 26] + 52;
  }

  function $Encode(this$static, rangeEncoder, symbol, posState) {
    if (symbol < 8) {
      $Encode_3(rangeEncoder, this$static._choice, 0, 0);
      $Encode_2(this$static._lowCoder[posState], rangeEncoder, symbol);
    } else {
      symbol -= 8;
      $Encode_3(rangeEncoder, this$static._choice, 0, 1);
      if (symbol < 8) {
        $Encode_3(rangeEncoder, this$static._choice, 1, 0);
        $Encode_2(this$static._midCoder[posState], rangeEncoder, symbol);
      } else {
        $Encode_3(rangeEncoder, this$static._choice, 1, 1);
        $Encode_2(this$static._highCoder, rangeEncoder, symbol - 8);
      }
    }
  }

  function $Encoder$LenEncoder(this$static) {
    this$static._choice = initDim(2);
    this$static._lowCoder = initDim(16);
    this$static._midCoder = initDim(16);
    this$static._highCoder = $BitTreeEncoder({}, 8);
    for (var posState = 0; posState < 16; ++posState) {
      this$static._lowCoder[posState] = $BitTreeEncoder({}, 3);
      this$static._midCoder[posState] = $BitTreeEncoder({}, 3);
    }
    return this$static;
  }

  function $Init_2(this$static, numPosStates) {
    InitBitModels(this$static._choice);
    for (var posState = 0; posState < numPosStates; ++posState) {
      InitBitModels(this$static._lowCoder[posState].Models);
      InitBitModels(this$static._midCoder[posState].Models);
    }
    InitBitModels(this$static._highCoder.Models);
  }

  function $SetPrices(this$static, posState, numSymbols, prices, st) {
    var a0, a1, b0, b1, i;
    a0 = ProbPrices[this$static._choice[0] >>> 2];
    a1 = ProbPrices[(2048 - this$static._choice[0]) >>> 2];
    b0 = a1 + ProbPrices[this$static._choice[1] >>> 2];
    b1 = a1 + ProbPrices[(2048 - this$static._choice[1]) >>> 2];
    i = 0;
    for (i = 0; i < 8; ++i) {
      if (i >= numSymbols) return;
      prices[st + i] = a0 + $GetPrice_1(this$static._lowCoder[posState], i);
    }
    for (; i < 16; ++i) {
      if (i >= numSymbols) return;
      prices[st + i] = b0 + $GetPrice_1(this$static._midCoder[posState], i - 8);
    }
    for (; i < numSymbols; ++i) {
      prices[st + i] = b1 + $GetPrice_1(this$static._highCoder, i - 8 - 8);
    }
  }

  function $Encode_0(this$static, rangeEncoder, symbol, posState) {
    $Encode(this$static, rangeEncoder, symbol, posState);
    if (--this$static._counters[posState] == 0) {
      $SetPrices(this$static, posState, this$static._tableSize, this$static._prices, posState * 272);
      this$static._counters[posState] = this$static._tableSize;
    }
  }

  function $Encoder$LenPriceTableEncoder(this$static) {
    $Encoder$LenEncoder(this$static);
    this$static._prices = [];
    this$static._counters = [];
    return this$static;
  }

  function $GetPrice(this$static, symbol, posState) {
    return this$static._prices[posState * 272 + symbol];
  }

  function $UpdateTables(this$static, numPosStates) {
    for (var posState = 0; posState < numPosStates; ++posState) {
      $SetPrices(this$static, posState, this$static._tableSize, this$static._prices, posState * 272);
      this$static._counters[posState] = this$static._tableSize;
    }
  }

  function $Create_1(this$static, numPosBits, numPrevBits) {
    var i, numStates;
    if (
      this$static.m_Coders != null &&
      this$static.m_NumPrevBits == numPrevBits &&
      this$static.m_NumPosBits == numPosBits
    ) {
      return;
    }
    this$static.m_NumPosBits = numPosBits;
    this$static.m_PosMask = (1 << numPosBits) - 1;
    this$static.m_NumPrevBits = numPrevBits;
    numStates = 1 << (this$static.m_NumPrevBits + this$static.m_NumPosBits);
    this$static.m_Coders = initDim(numStates);
    for (i = 0; i < numStates; ++i) {
      this$static.m_Coders[i] = $Encoder$LiteralEncoder$Encoder2({});
    }
  }

  function $GetSubCoder(this$static, pos, prevByte) {
    return this$static.m_Coders[
      ((pos & this$static.m_PosMask) << this$static.m_NumPrevBits) +
        ((prevByte & 255) >>> (8 - this$static.m_NumPrevBits))
    ];
  }

  function $Init_3(this$static) {
    var i,
      numStates = 1 << (this$static.m_NumPrevBits + this$static.m_NumPosBits);
    for (i = 0; i < numStates; ++i) {
      InitBitModels(this$static.m_Coders[i].m_Encoders);
    }
  }

  function $Encode_1(this$static, rangeEncoder, symbol) {
    var bit,
      i,
      context = 1;
    for (i = 7; i >= 0; --i) {
      bit = (symbol >> i) & 1;
      $Encode_3(rangeEncoder, this$static.m_Encoders, context, bit);
      context = (context << 1) | bit;
    }
  }

  function $EncodeMatched(this$static, rangeEncoder, matchByte, symbol) {
    var bit,
      i,
      matchBit,
      state,
      same = 1,
      context = 1;
    for (i = 7; i >= 0; --i) {
      bit = (symbol >> i) & 1;
      state = context;
      if (same) {
        matchBit = (matchByte >> i) & 1;
        state += (1 + matchBit) << 8;
        same = matchBit == bit;
      }
      $Encode_3(rangeEncoder, this$static.m_Encoders, state, bit);
      context = (context << 1) | bit;
    }
  }

  function $Encoder$LiteralEncoder$Encoder2(this$static) {
    this$static.m_Encoders = initDim(768);
    return this$static;
  }

  function $GetPrice_0(this$static, matchMode, matchByte, symbol) {
    var bit,
      context = 1,
      i = 7,
      matchBit,
      price = 0;
    if (matchMode) {
      for (; i >= 0; --i) {
        matchBit = (matchByte >> i) & 1;
        bit = (symbol >> i) & 1;
        price += GetPrice(this$static.m_Encoders[((1 + matchBit) << 8) + context], bit);
        context = (context << 1) | bit;
        if (matchBit != bit) {
          --i;
          break;
        }
      }
    }
    for (; i >= 0; --i) {
      bit = (symbol >> i) & 1;
      price += GetPrice(this$static.m_Encoders[context], bit);
      context = (context << 1) | bit;
    }
    return price;
  }

  function $MakeAsChar(this$static) {
    this$static.BackPrev = -1;
    this$static.Prev1IsChar = 0;
  }

  function $MakeAsShortRep(this$static) {
    this$static.BackPrev = 0;
    this$static.Prev1IsChar = 0;
  }
  /** ce */
  /** ds */
  function $BitTreeDecoder(this$static, numBitLevels) {
    this$static.NumBitLevels = numBitLevels;
    this$static.Models = initDim(1 << numBitLevels);
    return this$static;
  }

  function $Decode_0(this$static, rangeDecoder) {
    var bitIndex,
      m = 1;
    for (bitIndex = this$static.NumBitLevels; bitIndex != 0; --bitIndex) {
      m = (m << 1) + $DecodeBit(rangeDecoder, this$static.Models, m);
    }
    return m - (1 << this$static.NumBitLevels);
  }

  function $ReverseDecode(this$static, rangeDecoder) {
    var bit,
      bitIndex,
      m = 1,
      symbol = 0;
    for (bitIndex = 0; bitIndex < this$static.NumBitLevels; ++bitIndex) {
      bit = $DecodeBit(rangeDecoder, this$static.Models, m);
      m <<= 1;
      m += bit;
      symbol |= bit << bitIndex;
    }
    return symbol;
  }

  function ReverseDecode(Models, startIndex, rangeDecoder, NumBitLevels) {
    var bit,
      bitIndex,
      m = 1,
      symbol = 0;
    for (bitIndex = 0; bitIndex < NumBitLevels; ++bitIndex) {
      bit = $DecodeBit(rangeDecoder, Models, startIndex + m);
      m <<= 1;
      m += bit;
      symbol |= bit << bitIndex;
    }
    return symbol;
  }
  /** de */
  /** cs */
  function $BitTreeEncoder(this$static, numBitLevels) {
    this$static.NumBitLevels = numBitLevels;
    this$static.Models = initDim(1 << numBitLevels);
    return this$static;
  }

  function $Encode_2(this$static, rangeEncoder, symbol) {
    var bit,
      bitIndex,
      m = 1;
    for (bitIndex = this$static.NumBitLevels; bitIndex != 0; ) {
      --bitIndex;
      bit = (symbol >>> bitIndex) & 1;
      $Encode_3(rangeEncoder, this$static.Models, m, bit);
      m = (m << 1) | bit;
    }
  }

  function $GetPrice_1(this$static, symbol) {
    var bit,
      bitIndex,
      m = 1,
      price = 0;
    for (bitIndex = this$static.NumBitLevels; bitIndex != 0; ) {
      --bitIndex;
      bit = (symbol >>> bitIndex) & 1;
      price += GetPrice(this$static.Models[m], bit);
      m = (m << 1) + bit;
    }
    return price;
  }

  function $ReverseEncode(this$static, rangeEncoder, symbol) {
    var bit,
      i,
      m = 1;
    for (i = 0; i < this$static.NumBitLevels; ++i) {
      bit = symbol & 1;
      $Encode_3(rangeEncoder, this$static.Models, m, bit);
      m = (m << 1) | bit;
      symbol >>= 1;
    }
  }

  function $ReverseGetPrice(this$static, symbol) {
    var bit,
      i,
      m = 1,
      price = 0;
    for (i = this$static.NumBitLevels; i != 0; --i) {
      bit = symbol & 1;
      symbol >>>= 1;
      price += GetPrice(this$static.Models[m], bit);
      m = (m << 1) | bit;
    }
    return price;
  }

  function ReverseEncode(Models, startIndex, rangeEncoder, NumBitLevels, symbol) {
    var bit,
      i,
      m = 1;
    for (i = 0; i < NumBitLevels; ++i) {
      bit = symbol & 1;
      $Encode_3(rangeEncoder, Models, startIndex + m, bit);
      m = (m << 1) | bit;
      symbol >>= 1;
    }
  }

  function ReverseGetPrice(Models, startIndex, NumBitLevels, symbol) {
    var bit,
      i,
      m = 1,
      price = 0;
    for (i = NumBitLevels; i != 0; --i) {
      bit = symbol & 1;
      symbol >>>= 1;
      price += ProbPrices[(((Models[startIndex + m] - bit) ^ -bit) & 2047) >>> 2];
      m = (m << 1) | bit;
    }
    return price;
  }
  /** ce */
  /** ds */
  function $DecodeBit(this$static, probs, index) {
    var newBound,
      prob = probs[index];
    newBound = (this$static.Range >>> 11) * prob;
    if ((this$static.Code ^ -2147483648) < (newBound ^ -2147483648)) {
      this$static.Range = newBound;
      probs[index] = ((prob + ((2048 - prob) >>> 5)) << 16) >> 16;
      if (!(this$static.Range & -16777216)) {
        this$static.Code = (this$static.Code << 8) | $read(this$static.Stream);
        this$static.Range <<= 8;
      }
      return 0;
    } else {
      this$static.Range -= newBound;
      this$static.Code -= newBound;
      probs[index] = ((prob - (prob >>> 5)) << 16) >> 16;
      if (!(this$static.Range & -16777216)) {
        this$static.Code = (this$static.Code << 8) | $read(this$static.Stream);
        this$static.Range <<= 8;
      }
      return 1;
    }
  }

  function $DecodeDirectBits(this$static, numTotalBits) {
    var i,
      t,
      result = 0;
    for (i = numTotalBits; i != 0; --i) {
      this$static.Range >>>= 1;
      t = (this$static.Code - this$static.Range) >>> 31;
      this$static.Code -= this$static.Range & (t - 1);
      result = (result << 1) | (1 - t);
      if (!(this$static.Range & -16777216)) {
        this$static.Code = (this$static.Code << 8) | $read(this$static.Stream);
        this$static.Range <<= 8;
      }
    }
    return result;
  }

  function $Init_8(this$static) {
    this$static.Code = 0;
    this$static.Range = -1;
    for (var i = 0; i < 5; ++i) {
      this$static.Code = (this$static.Code << 8) | $read(this$static.Stream);
    }
  }
  /** de */

  function InitBitModels(probs) {
    for (var i = probs.length - 1; i >= 0; --i) {
      probs[i] = 1024;
    }
  }
  /** cs */
  var ProbPrices = (function() {
    var end,
      i,
      j,
      start,
      ProbPrices = [];
    for (i = 8; i >= 0; --i) {
      start = 1 << (9 - i - 1);
      end = 1 << (9 - i);
      for (j = start; j < end; ++j) {
        ProbPrices[j] = (i << 6) + (((end - j) << 6) >>> (9 - i - 1));
      }
    }
    return ProbPrices;
  })();

  function $Encode_3(this$static, probs, index, symbol) {
    var newBound,
      prob = probs[index];
    newBound = (this$static.Range >>> 11) * prob;
    if (!symbol) {
      this$static.Range = newBound;
      probs[index] = ((prob + ((2048 - prob) >>> 5)) << 16) >> 16;
    } else {
      this$static.Low = add(this$static.Low, and(fromInt(newBound), [4294967295, 0]));
      this$static.Range -= newBound;
      probs[index] = ((prob - (prob >>> 5)) << 16) >> 16;
    }
    if (!(this$static.Range & -16777216)) {
      this$static.Range <<= 8;
      $ShiftLow(this$static);
    }
  }

  function $EncodeDirectBits(this$static, v, numTotalBits) {
    for (var i = numTotalBits - 1; i >= 0; --i) {
      this$static.Range >>>= 1;
      if (((v >>> i) & 1) == 1) {
        this$static.Low = add(this$static.Low, fromInt(this$static.Range));
      }
      if (!(this$static.Range & -16777216)) {
        this$static.Range <<= 8;
        $ShiftLow(this$static);
      }
    }
  }

  function $GetProcessedSizeAdd(this$static) {
    return add(add(fromInt(this$static._cacheSize), this$static._position), [4, 0]);
  }

  function $Init_9(this$static) {
    this$static._position = P0_longLit;
    this$static.Low = P0_longLit;
    this$static.Range = -1;
    this$static._cacheSize = 1;
    this$static._cache = 0;
  }

  function $ShiftLow(this$static) {
    var temp,
      LowHi = lowBits_0(shru(this$static.Low, 32));
    if (LowHi != 0 || compare(this$static.Low, [4278190080, 0]) < 0) {
      this$static._position = add(this$static._position, fromInt(this$static._cacheSize));
      temp = this$static._cache;
      do {
        $write(this$static.Stream, temp + LowHi);
        temp = 255;
      } while (--this$static._cacheSize != 0);
      this$static._cache = lowBits_0(this$static.Low) >>> 24;
    }
    ++this$static._cacheSize;
    this$static.Low = shl(and(this$static.Low, [16777215, 0]), 8);
  }

  function GetPrice(Prob, symbol) {
    return ProbPrices[(((Prob - symbol) ^ -symbol) & 2047) >>> 2];
  }

  /** ce */
  /** ds */
  function decode(utf) {
    var i = 0,
      j = 0,
      x,
      y,
      z,
      l = utf.length,
      buf = [],
      charCodes = [];
    for (; i < l; ++i, ++j) {
      x = utf[i] & 255;
      if (!(x & 128)) {
        if (!x) {
          /// It appears that this is binary data, so it cannot be converted to a string, so just send it back.
          return utf;
        }
        charCodes[j] = x;
      } else if ((x & 224) == 192) {
        if (i + 1 >= l) {
          /// It appears that this is binary data, so it cannot be converted to a string, so just send it back.
          return utf;
        }
        y = utf[++i] & 255;
        if ((y & 192) != 128) {
          /// It appears that this is binary data, so it cannot be converted to a string, so just send it back.
          return utf;
        }
        charCodes[j] = ((x & 31) << 6) | (y & 63);
      } else if ((x & 240) == 224) {
        if (i + 2 >= l) {
          /// It appears that this is binary data, so it cannot be converted to a string, so just send it back.
          return utf;
        }
        y = utf[++i] & 255;
        if ((y & 192) != 128) {
          /// It appears that this is binary data, so it cannot be converted to a string, so just send it back.
          return utf;
        }
        z = utf[++i] & 255;
        if ((z & 192) != 128) {
          /// It appears that this is binary data, so it cannot be converted to a string, so just send it back.
          return utf;
        }
        charCodes[j] = ((x & 15) << 12) | ((y & 63) << 6) | (z & 63);
      } else {
        /// It appears that this is binary data, so it cannot be converted to a string, so just send it back.
        return utf;
      }
      if (j == 16383) {
        buf.push(String.fromCharCode.apply(String, charCodes));
        j = -1;
      }
    }
    if (j > 0) {
      charCodes.length = j;
      buf.push(String.fromCharCode.apply(String, charCodes));
    }
    return buf.join('');
  }
  /** de */
  /** cs */
  function encode(s) {
    var ch,
      chars = [],
      data,
      elen = 0,
      i,
      l = s.length;
    /// Be able to handle binary arrays and buffers.
    if (typeof s == 'object') {
      return s;
    } else {
      $getChars(s, 0, l, chars, 0);
    }
    /// Add extra spaces in the array to break up the unicode symbols.
    for (i = 0; i < l; ++i) {
      ch = chars[i];
      if (ch >= 1 && ch <= 127) {
        ++elen;
      } else if (!ch || (ch >= 128 && ch <= 2047)) {
        elen += 2;
      } else {
        elen += 3;
      }
    }
    data = [];
    elen = 0;
    for (i = 0; i < l; ++i) {
      ch = chars[i];
      if (ch >= 1 && ch <= 127) {
        data[elen++] = (ch << 24) >> 24;
      } else if (!ch || (ch >= 128 && ch <= 2047)) {
        data[elen++] = ((192 | ((ch >> 6) & 31)) << 24) >> 24;
        data[elen++] = ((128 | (ch & 63)) << 24) >> 24;
      } else {
        data[elen++] = ((224 | ((ch >> 12) & 15)) << 24) >> 24;
        data[elen++] = ((128 | ((ch >> 6) & 63)) << 24) >> 24;
        data[elen++] = ((128 | (ch & 63)) << 24) >> 24;
      }
    }
    return data;
  }
  /** ce */

  function toDouble(a) {
    return a[1] + a[0];
  }

  /** cs */
  function compress(str, mode, on_finish, on_progress) {
    var this$static = {},
      percent,
      cbn, /// A callback number should be supplied instead of on_finish() if we are using Web Workers.
      sync = typeof on_finish == 'undefined' && typeof on_progress == 'undefined';

    if (typeof on_finish != 'function') {
      cbn = on_finish;
      on_finish = on_progress = 0;
    }

    on_progress =
      on_progress ||
      function(percent) {
        if (typeof cbn == 'undefined') return;

        return update_progress(percent, cbn);
      };

    on_finish =
      on_finish ||
      function(res, err) {
        if (typeof cbn == 'undefined') return;

        return postMessage({
          action: action_compress,
          cbn: cbn,
          result: res,
          error: err,
        });
      };

    if (sync) {
      this$static.c = $LZMAByteArrayCompressor({}, encode(str), get_mode_obj(mode));
      while ($processChunk(this$static.c.chunker));
      return $toByteArray(this$static.c.output);
    }

    try {
      this$static.c = $LZMAByteArrayCompressor({}, encode(str), get_mode_obj(mode));

      on_progress(0);
    } catch (err) {
      return on_finish(null, err);
    }

    function do_action() {
      try {
        var res,
          start = new Date().getTime();

        while ($processChunk(this$static.c.chunker)) {
          percent = toDouble(this$static.c.chunker.inBytesProcessed) / toDouble(this$static.c.length_0);
          /// If about 200 miliseconds have passed, update the progress.
          if (new Date().getTime() - start > 200) {
            on_progress(percent);

            wait(do_action, 0);
            return 0;
          }
        }

        on_progress(1);

        res = $toByteArray(this$static.c.output);

        /// delay so we don’t catch errors from the on_finish handler
        wait(on_finish.bind(null, res), 0);
      } catch (err) {
        on_finish(null, err);
      }
    }

    ///NOTE: We need to wait to make sure it is always async.
    wait(do_action, 0);
  }
  /** ce */
  /** ds */
  function decompress(byte_arr, on_finish, on_progress) {
    var this$static = {},
      percent,
      cbn, /// A callback number should be supplied instead of on_finish() if we are using Web Workers.
      has_progress,
      len,
      sync = typeof on_finish == 'undefined' && typeof on_progress == 'undefined';

    if (typeof on_finish != 'function') {
      cbn = on_finish;
      on_finish = on_progress = 0;
    }

    on_progress =
      on_progress ||
      function(percent) {
        if (typeof cbn == 'undefined') return;

        return update_progress(has_progress ? percent : -1, cbn);
      };

    on_finish =
      on_finish ||
      function(res, err) {
        if (typeof cbn == 'undefined') return;

        return postMessage({
          action: action_decompress,
          cbn: cbn,
          result: res,
          error: err,
        });
      };

    if (sync) {
      this$static.d = $LZMAByteArrayDecompressor({}, byte_arr);
      while ($processChunk(this$static.d.chunker));
      return decode($toByteArray(this$static.d.output));
    }

    try {
      this$static.d = $LZMAByteArrayDecompressor({}, byte_arr);

      len = toDouble(this$static.d.length_0);

      ///NOTE: If the data was created via a stream, it will not have a length value, and therefore we can't calculate the progress.
      has_progress = len > -1;

      on_progress(0);
    } catch (err) {
      return on_finish(null, err);
    }

    function do_action() {
      try {
        var res,
          i = 0,
          start = new Date().getTime();
        while ($processChunk(this$static.d.chunker)) {
          if (++i % 1000 == 0 && new Date().getTime() - start > 200) {
            if (has_progress) {
              percent = toDouble(this$static.d.chunker.decoder.nowPos64) / len;
              /// If about 200 miliseconds have passed, update the progress.
              on_progress(percent);
            }

            ///NOTE: This allows other code to run, like the browser to update.
            wait(do_action, 0);
            return 0;
          }
        }

        on_progress(1);

        res = decode($toByteArray(this$static.d.output));

        /// delay so we don’t catch errors from the on_finish handler
        wait(on_finish.bind(null, res), 0);
      } catch (err) {
        on_finish(null, err);
      }
    }

    ///NOTE: We need to wait to make sure it is always async.
    wait(do_action, 0);
  }
  /** de */
  /** cs */
  var get_mode_obj = (function() {
    /// s is dictionarySize
    /// f is fb
    /// m is matchFinder
    ///NOTE: Because some values are always the same, they have been removed.
    /// lc is always 3
    /// lp is always 0
    /// pb is always 2
    var modes = [
      { s: 16, f: 64, m: 0 },
      { s: 20, f: 64, m: 0 },
      { s: 19, f: 64, m: 1 },
      { s: 20, f: 64, m: 1 },
      { s: 21, f: 128, m: 1 },
      { s: 22, f: 128, m: 1 },
      { s: 23, f: 128, m: 1 },
      { s: 24, f: 255, m: 1 },
      { s: 25, f: 255, m: 1 },
    ];

    return function(mode) {
      return modes[mode - 1] || modes[6];
    };
  })();
  /** ce */

  /// If we're in a Web Worker, create the onmessage() communication channel.
  ///NOTE: This seems to be the most reliable way to detect this.
  if (typeof onmessage != 'undefined' && (typeof window == 'undefined' || typeof window.document == 'undefined')) {
    (function() {
      /* jshint -W020 */
      /// Create the global onmessage function.
      onmessage = function(e) {
        if (e && e.data) {
          /** xs */
          if (e.data.action == action_decompress) {
            LZMA.decompress(e.data.data, e.data.cbn);
          } else if (e.data.action == action_compress) {
            LZMA.compress(e.data.data, e.data.mode, e.data.cbn);
          }
          /** xe */
          /// co:if (e.data.action == action_compress) {
          /// co:    LZMA.compress(e.data.data, e.data.mode, e.data.cbn);
          /// co:}
          /// do:if (e.data.action == action_decompress) {
          /// do:    LZMA.decompress(e.data.data, e.data.cbn);
          /// do:}
        }
      };
    })();
  }

  return {
    /** xs */
    compress: compress,
    decompress: decompress,
    /** xe */
    /// co:compress:   compress
    /// do:decompress: decompress
  };
})();

/// This is used by browsers that do not support web workers (and possibly Node.js).
this.LZMA = this.LZMA_WORKER = LZMA;
